16namespace draw_routines {
20constexpr int kThievesTownEastAtticRoomId = 0x65;
24 return tiles[index % tiles.size()];
28 int h, std::span<const gfx::TileInfo> tiles,
29 size_t start_index = 0) {
33 size_t index = start_index;
34 for (
int x = 0; x < w; ++x) {
35 for (
int y = 0; y < h; ++y) {
43 int h, std::span<const gfx::TileInfo> tiles,
44 size_t start_index = 0) {
48 size_t index = start_index;
49 for (
int y = 0; y < h; ++y) {
50 for (
int x = 0; x < w; ++x) {
60 columns, 3, ctx.
tiles, start_index);
65 ctx.
tiles, start_index);
70 ctx.
tiles, start_index);
80 if (ctx.
tiles.size() < 64)
90 std::span<const gfx::TileInfo> tiles) {
95 std::span<const gfx::TileInfo> tiles) {
104 return object_id == 0x0130 || object_id == 0x0131 || object_id == 0x0F9B ||
109 return object_id >= 0x0F9E && object_id <= 0x0FA1;
113 return object_id >= 0x0FA6 && object_id <= 0x0FA9;
117 return object_id == 0x0FA8 || object_id == 0x0FA9;
124 if (ctx.
tiles.size() < 8)
141 constexpr size_t kSpanTiles = 40;
142 const bool use_open_tiles = ctx.
state !=
nullptr &&
144 ctx.
tiles.size() >= kSpanTiles * 2;
145 const size_t start_index = use_open_tiles ? kSpanTiles : 0;
146 if (ctx.
tiles.size() < start_index + kSpanTiles)
154 if (index >= ctx.
tiles.size())
162 size_t start_index,
int columns) {
163 for (
int x = 0; x < columns; ++x) {
164 for (
int y = 0; y < 3; ++y) {
171 size_t start_index) {
179 size_t start_index) {
190 0x3C15, 0x3C15, 0x3C15};
193 std::array<gfx::TileInfo, 3> fill_tiles;
194 for (
size_t i = 0; i < fill_tiles.size(); ++i) {
196 if (ctx.
rom !=
nullptr) {
198 static_cast<int>(i * 2));
211 for (
int x = 0; x < column_count; ++x) {
214 for (
int y = 1; y < height - 1; ++y) {
219 ctx.
object.
y_ + height - 1, fill_tiles[2]);
226 for (
int i = 0; i < direction; ++i) {
237 size_t start_index,
int fill_width) {
240 for (
int i = 0; i < fill_width; ++i) {
244 const int left_cap_x = 1 + fill_width;
247 for (
int i = 0; i < 4; ++i) {
251 const int right_cap_x = left_cap_x + 5;
254 for (
int i = 0; i < fill_width; ++i) {
267 if (!is_open && ctx.
state) {
274 size_t start_index = is_open && ctx.
tiles.size() >= 32 ? 16 : 0;
275 for (
int x = 0; x < 4; ++x) {
276 for (
int y = 0; y < 4; ++y) {
279 ctx.
tiles[start_index +
static_cast<size_t>(x * 4 + y)]);
285 size_t start_index = 0;
286 if (is_open && ctx.
object.
id_ == 0xF99 && ctx.
tiles.size() >= 8) {
289 if (ctx.
tiles.size() < start_index + 4) {
294 ctx.
tiles[start_index]);
296 ctx.
tiles[start_index + 1]);
298 ctx.
tiles[start_index + 2]);
317 if (ctx.
tiles.size() >= 1) {
329 if (!result.ok() || !result.value() || result.value()->IsEmpty()) {
331 if (ctx.
tiles.size() >= 1) {
338 const auto& custom_obj = *result.value();
340 for (
const auto& entry : custom_obj.tiles) {
343 uint8_t lo =
static_cast<uint8_t
>(entry.tile_data & 0xFF);
344 uint8_t hi =
static_cast<uint8_t
>((entry.tile_data >> 8) & 0xFF);
349 int draw_x = ctx.
object.
x_ + entry.rel_x;
350 int draw_y = ctx.
object.
y_ + entry.rel_y;
363 if (ctx.
tiles.size() >= 2) {
368 if (ctx.
tiles.size() >
static_cast<size_t>(tile_index)) {
370 ctx.
tiles[tile_index]);
378 if (ctx.
tiles.empty()) {
390 if (ctx.
tiles.size() >= 4) {
407 if (ctx.
tiles.size() >=
static_cast<size_t>(width * height)) {
408 for (
int y = 0; y < height; ++y) {
409 for (
int x = 0; x < width; ++x) {
412 ctx.
tiles[y * width + x]);
426 Draw1x3NRightwards(ctx, 6, 0);
431 Draw1x3NRightwards(ctx, 6, 0);
439 if (ctx.
tiles.empty())
443 for (
int x = 0; x < 3; ++x) {
446 TileAtWrapped(ctx.
tiles,
static_cast<size_t>(x)));
450 for (
int y = 1; y <= 3; ++y) {
451 for (
int x = 0; x < 3; ++x) {
454 TileAtWrapped(ctx.
tiles,
static_cast<size_t>(3 + x)));
459 for (
int x = 0; x < 3; ++x) {
462 TileAtWrapped(ctx.
tiles,
static_cast<size_t>(6 + x)));
469 if (ctx.
tiles.empty())
471 Draw1x3NRightwards(ctx, 4, 0, 0);
472 Draw1x3NRightwards(ctx, 4, 12, 3);
485 if (ctx.
tiles.size() < 32)
487 Draw4x4ColumnMajor(ctx, 0, 0, 0);
488 Draw4x4ColumnMajor(ctx, 0, 2, 0);
489 Draw4x4ColumnMajor(ctx, 0, 6, 16);
498 if (ctx.
state !=
nullptr &&
502 DrawFloorLightGrid(ctx);
507 DrawFloorLightGrid(ctx);
512 Draw4x4ColumnMajor(ctx, 0, 0, 0);
523 if (ctx.
tiles.empty())
525 Draw1x3NRightwards(ctx, 3, 0, 0);
526 Draw1x3NRightwards(ctx, 3, 9, 3);
532 if (ctx.
tiles.empty())
535 Draw4x4ColumnMajor(ctx, 2, 0, 0);
536 Draw4x4ColumnMajor(ctx, 0, 4, 16);
537 Draw4x4ColumnMajor(ctx, 4, 4, 16);
543 if (ctx.
tiles.size() < 4)
558 if (ctx.
tiles.size() < 16)
562 for (
int x = 0; x < 4; ++x) {
563 for (
int y = 0; y < 4; ++y) {
572 if (ctx.
tiles.size() < 12)
576 for (
int x = 0; x < 4; ++x) {
577 for (
int y = 0; y < 3; ++y) {
589 ctx.
tiles.size() < 2) {
593 constexpr std::array<int, 3> kTopRows = {0, 3, 6};
594 constexpr std::array<int, 3> kBottomRows = {1, 4, 7};
595 for (
int col = 0; col < 3; ++col) {
596 const int x = ctx.
object.
x_ + col * 2;
597 for (
int row : kTopRows) {
601 for (
int row : kBottomRows) {
616 if (ctx.
tiles.empty())
620 const int middle_columns = (size + 1) * 2;
622 Draw1x5Column(ctx, 0, 0);
623 for (
int i = 0; i < middle_columns; ++i) {
624 Draw1x5Column(ctx, 1 + i, 5);
626 Draw1x5Column(ctx, 1 + middle_columns, 10);
632 if (ctx.
tiles.empty())
636 const int middle_columns = (size + 1) * 2;
640 for (
int i = 0; i < middle_columns; ++i) {
663 "Draw4x4BlocksIn4x4SuperSquare: obj=0x%03X pos=(%d,%d) size=0x%02X "
664 "tiles=%zu size_x=%d size_y=%d",
666 ctx.
tiles.size(), size_x, size_y);
668 if (ctx.
tiles.empty()) {
670 "Draw4x4BlocksIn4x4SuperSquare: SKIPPING - no tiles loaded!");
675 const auto& tile = ctx.
tiles[0];
677 "Draw4x4BlocksIn4x4SuperSquare: tile[0] id=%d palette=%d", tile.id_,
680 for (
int sy = 0; sy < size_y; ++sy) {
681 for (
int sx = 0; sx < size_x; ++sx) {
683 int base_x = ctx.
object.
x_ + (sx * 4);
684 int base_y = ctx.
object.
y_ + (sy * 4);
687 for (
int y = 0; y < 4; ++y) {
688 for (
int x = 0; x < 4; ++x) {
703 if (ctx.
tiles.empty())
706 const auto& tile = ctx.
tiles[0];
707 for (
int sy = 0; sy < size_y; ++sy) {
708 for (
int sx = 0; sx < size_x; ++sx) {
709 int base_x = ctx.
object.
x_ + (sx * 3);
710 int base_y = ctx.
object.
y_ + (sy * 3);
712 for (
int y = 0; y < 3; ++y) {
713 for (
int x = 0; x < 3; ++x) {
729 if (ctx.
tiles.empty())
731 if (ctx.
tiles.size() < 8) {
738 for (
int sy = 0; sy < size_y; ++sy) {
739 for (
int sx = 0; sx < size_x; ++sx) {
740 int base_x = ctx.
object.
x_ + (sx * 4);
741 int base_y = ctx.
object.
y_ + (sy * 4);
755 if (ctx.
tiles.size() < 8) {
760 for (
int sy = 0; sy < size_y; ++sy) {
761 for (
int sx = 0; sx < size_x; ++sx) {
762 int base_x = ctx.
object.
x_ + (sx * 4);
763 int base_y = ctx.
object.
y_ + (sy * 4);
776 if (ctx.
tiles.size() < 8) {
781 for (
int sy = 0; sy < size_y; ++sy) {
782 for (
int sx = 0; sx < size_x; ++sx) {
783 int base_x = ctx.
object.
x_ + (sx * 4);
784 int base_y = ctx.
object.
y_ + (sy * 4);
796 if (ctx.
tiles.size() < 24)
813 for (
int xx = 1; xx < max; ++xx) {
814 for (
int yy = 1; yy < max; ++yy) {
824 for (
int yy = 1; yy < max; ++yy) {
838 if (ctx.
tiles.size() < 4)
841 for (
int sy = 0; sy < size_y; ++sy) {
842 for (
int sx = 0; sx < size_x; ++sx) {
843 int base_x = ctx.
object.
x_ + (sx * 2);
844 int base_y = ctx.
object.
y_ + (sy * 2);
862 if (ctx.
tiles.size() < 16)
865 int right_x = ctx.
object.
x_ + (3 + (size_x * 2));
866 int bottom_y = ctx.
object.
y_ + (3 + (size_y * 2));
869 for (
int xx = 0; xx < size_x + 1; ++xx) {
870 for (
int yy = 0; yy < size_y + 1; ++yy) {
871 int base_x = ctx.
object.
x_ + (xx * 2);
872 int base_y = ctx.
object.
y_ + (yy * 2);
885 for (
int yy = 0; yy < size_y + 1; ++yy) {
886 int base_y = ctx.
object.
y_ + (yy * 2);
899 for (
int xx = 0; xx < size_x + 1; ++xx) {
900 int base_x = ctx.
object.
x_ + (xx * 2);
931 int count_x = size_x + 2;
932 int count_y = size_y + 2;
934 if (ctx.
tiles.empty())
936 if (ctx.
tiles.size() < 8) {
938 for (
int yy = 0; yy < count_y; ++yy) {
939 for (
int xx = 0; xx < count_x; ++xx) {
940 int base_x = ctx.
object.
x_ + (xx * 4);
941 int base_y = ctx.
object.
y_ + (yy * 4);
943 ctx.
tiles[
static_cast<size_t>((xx + yy) % ctx.
tiles.size())];
944 for (
int y = 0; y < 4; ++y) {
945 for (
int x = 0; x < 4; ++x) {
955 for (
int yy = 0; yy < count_y; ++yy) {
956 for (
int xx = 0; xx < count_x; ++xx) {
957 int base_x = ctx.
object.
x_ + (xx * 4);
958 int base_y = ctx.
object.
y_ + (yy * 4);
960 for (
int x = 0; x < 4; ++x) {
984 if (ctx.
tiles.size() < 16)
1009 if (ctx.
tiles.size() < 12)
1024 if (ctx.
tiles.size() < 16)
1038 if (ctx.
tiles.size() < 16)
1042 !IsStraightInterroomLower(ctx.
object.
id_)) {
1047 const bool south_lower = IsSouthLowerStraightInterroomStairs(ctx.
object.
id_);
1048 size_t tile_index = 0;
1049 for (
int col = 0; col < 4; ++col) {
1050 for (
int row = 0; row < 4; ++row) {
1051 const auto& tile = TileAtWrapped(ctx.
tiles, tile_index++);
1054 if ((!south_lower && row == 0) || (south_lower && row == 3)) {
1073 if (ctx.
tiles.size() < 6) {
1083 tile.horizontal_mirror_ =
true;
1087 for (
int col = 0; col < 5; ++col) {
1088 const int left_x = base_x + 2 + col;
1089 const int right_x = base_x + 9 + col;
1095 with_horizontal_mirror(ctx.
tiles[2]));
1099 with_horizontal_mirror(ctx.
tiles[4]));
1103 with_horizontal_mirror(ctx.
tiles[5]));
1108 with_horizontal_mirror(ctx.
tiles[0]));
1109 for (
int x_offset : {1, 7, 8, 14}) {
1116 with_horizontal_mirror(ctx.
tiles[3]));
1133 if (ctx.
tiles.size() < 16) {
1140 const bool is_open = ctx.
state !=
nullptr &&
1142 ctx.
tiles.size() >= 32;
1143 const size_t state_offset = is_open ? 16 : 0;
1145 for (
int block_y = 0; block_y < 2; ++block_y) {
1146 for (
int block_x = 0; block_x < 2; ++block_x) {
1147 const size_t block_offset =
1148 state_offset +
static_cast<size_t>((block_y * 2 + block_x) * 4);
1149 for (
int x = 0; x < 2; ++x) {
1150 for (
int y = 0; y < 2; ++y) {
1154 ctx.
tiles[block_offset +
static_cast<size_t>(x * 2 + y)]);
1164 ctx.
tiles.size() < 24) {
1170 const int height = direction * 2 + 6;
1174 DrawMovingWallFill(ctx, ctx.
object.
x_ - column_count, column_count, height);
1175 DrawMovingWallPlatform(ctx, direction);
1181 ctx.
tiles.size() < 24) {
1187 const int height = direction * 2 + 6;
1191 DrawMovingWallPlatform(ctx, direction);
1192 DrawMovingWallFill(ctx, ctx.
object.
x_ + 3, column_count, height);
1203 if (row_count <= 0 || tile_offset < 0 || ctx.
tiles.empty()) {
1207 if (tile_offset >=
static_cast<int>(ctx.
tiles.size())) {
1211 const int available_tiles =
static_cast<int>(ctx.
tiles.size()) - tile_offset;
1213 const int rows_to_draw = std::min(row_count, available_rows);
1215 for (
int row = 0; row < rows_to_draw; ++row) {
1220 ctx.
tiles[row_base + col]);
1235 const bool water_active =
1238 const int row_count = water_active ? 5 : 3;
1239 const int tile_offset = water_active ? 12 : 0;
1240 DrawWaterFaceRows(ctx, row_count, tile_offset);
1246 DrawWaterFaceRows(ctx, 5, 0);
1252 DrawWaterFaceRows(ctx, 7, 0);
1266 if (ctx.
tiles.size() < 68)
1269 const int size_x = (ctx.
object.
size_ >> 2) & 0x03;
1271 const int width_blocks = size_x + 4;
1272 const int height_blocks = size_y + 1;
1275 DrawPlatform1x3Rightwards(ctx, 0, 0, 0,
1277 for (
int x = 0; x < width_blocks; ++x) {
1278 DrawPlatform1x3Rightwards(ctx, 3 + x * 2, 0,
1281 DrawPlatform1x3Rightwards(ctx, 3 + width_blocks * 2, 0,
1285 for (
int y = 0; y < height_blocks; ++y) {
1286 const int dy = 3 + y * 2;
1287 DrawPlatform3x2(ctx, 0, dy, 24);
1288 for (
int x = 0; x < width_blocks; ++x) {
1289 DrawPlatform2x2(ctx, 3 + x * 2, dy, 30);
1291 DrawPlatform3x2(ctx, 3 + width_blocks * 2, dy,
1296 const int bottom_y = 3 + height_blocks * 2;
1297 DrawPlatform1x3Rightwards(ctx, 0, bottom_y, 40,
1299 for (
int x = 0; x < width_blocks; ++x) {
1300 DrawPlatform1x3Rightwards(ctx, 3 + x * 2, bottom_y,
1303 DrawPlatform1x3Rightwards(ctx, 3 + width_blocks * 2, bottom_y,
1308 DrawPlatform2x2(ctx, width_blocks + 2,
1309 bottom_y - (height_blocks + 1),
1317 if (ctx.
tiles.size() < 21)
1320 const int size_x = (ctx.
object.
size_ >> 2) & 0x03;
1322 const int fill_width = size_x + 1;
1323 const int body_rows = size_y * 2 + 5;
1325 for (
int row = 0; row < body_rows; ++row) {
1326 DrawOpenChestPlatformSegment(ctx, row, 0, fill_width);
1328 DrawOpenChestPlatformSegment(ctx, body_rows, 1, fill_width);
1329 DrawOpenChestPlatformSegment(ctx, body_rows + 1, 2,
1337 if (ctx.
tiles.size() < 3)
1340 for (
int x = 0; x < width; ++x) {
1341 size_t tile_idx = (x == 0) ? 0 : ((x == width - 1) ? 2 : 1);
1351 if (ctx.
tiles.empty())
1354 for (
int y = 0; y < height; ++y) {
1373 .draws_to_both_bgs =
false,
1384 .draws_to_both_bgs =
false,
1392 .name =
"DoorSwitcherer",
1394 .draws_to_both_bgs =
false,
1403 .name =
"SomariaLine",
1405 .draws_to_both_bgs =
false,
1414 .name =
"WaterFace",
1416 .draws_to_both_bgs =
false,
1429 .name =
"4x4BlocksIn4x4SuperSquare",
1431 .draws_to_both_bgs =
false,
1439 .name =
"3x3FloorIn4x4SuperSquare",
1441 .draws_to_both_bgs =
false,
1449 .name =
"4x4FloorIn4x4SuperSquare",
1451 .draws_to_both_bgs =
false,
1459 .name =
"4x4FloorOneIn4x4SuperSquare",
1461 .draws_to_both_bgs =
false,
1469 .name =
"4x4FloorTwoIn4x4SuperSquare",
1471 .draws_to_both_bgs =
false,
1479 .name =
"BigHole4x4_1to16",
1481 .draws_to_both_bgs =
false,
1489 .name =
"Spike2x2In4x4SuperSquare",
1491 .draws_to_both_bgs =
false,
1499 .name =
"TableRock4x4_1to16",
1501 .draws_to_both_bgs =
false,
1509 .name =
"WaterOverlay8x8_1to16",
1511 .draws_to_both_bgs =
false,
1520 .name =
"InterRoomFatStairsUp",
1522 .draws_to_both_bgs =
false,
1531 .name =
"InterRoomFatStairsDownA",
1533 .draws_to_both_bgs =
false,
1542 .name =
"InterRoomFatStairsDownB",
1544 .draws_to_both_bgs =
false,
1553 .name =
"AutoStairs",
1555 .draws_to_both_bgs =
false,
1564 .name =
"StraightInterRoomStairs",
1566 .draws_to_both_bgs =
false,
1576 .name =
"SpiralStairsGoingUpUpper",
1579 .draws_to_both_bgs =
false,
1588 .name =
"SpiralStairsGoingDownUpper",
1591 .draws_to_both_bgs =
false,
1600 .name =
"SpiralStairsGoingUpLower",
1603 .draws_to_both_bgs =
false,
1612 .name =
"SpiralStairsGoingDownLower",
1615 .draws_to_both_bgs =
false,
1624 .name =
"WaterHopStairsA",
1625 .function = DrawWaterHopStairsA,
1626 .draws_to_both_bgs =
false,
1635 .name =
"WaterHopStairsB",
1636 .function = DrawWaterHopStairsB,
1637 .draws_to_both_bgs =
true,
1646 .name =
"DamFloodGate",
1647 .function = DrawDamFloodGate,
1648 .draws_to_both_bgs =
false,
1658 .name =
"BigKeyLock",
1660 .draws_to_both_bgs =
false,
1669 .name =
"BombableFloor",
1671 .draws_to_both_bgs =
false,
1681 .name =
"EmptyWaterFace",
1683 .draws_to_both_bgs =
false,
1692 .name =
"SpittingWaterFace",
1694 .draws_to_both_bgs =
false,
1703 .name =
"DrenchingWaterFace",
1705 .draws_to_both_bgs =
false,
1716 .name =
"PrisonCell",
1718 .draws_to_both_bgs =
false,
1729 .draws_to_both_bgs =
false,
1737 .name =
"Rightwards3x6",
1739 .draws_to_both_bgs =
false,
1747 .name =
"Utility6x3",
1749 .draws_to_both_bgs =
false,
1757 .name =
"Utility3x5",
1759 .draws_to_both_bgs =
false,
1767 .name =
"VerticalTurtleRockPipe",
1769 .draws_to_both_bgs =
false,
1777 .name =
"HorizontalTurtleRockPipe",
1779 .draws_to_both_bgs =
false,
1787 .name =
"LightBeam",
1789 .draws_to_both_bgs =
false,
1798 .name =
"BigLightBeam",
1800 .draws_to_both_bgs =
false,
1809 .name =
"FloorLight",
1811 .draws_to_both_bgs =
false,
1820 .name =
"BossShell4x4",
1822 .draws_to_both_bgs =
false,
1830 .name =
"SolidWallDecor3x4",
1832 .draws_to_both_bgs =
false,
1840 .name =
"ArcheryGameTargetDoor",
1842 .draws_to_both_bgs =
false,
1850 .name =
"GanonTriforceFloorDecor",
1852 .draws_to_both_bgs =
false,
1860 .name =
"Single2x2",
1862 .draws_to_both_bgs =
false,
1871 .name =
"Single4x4",
1873 .draws_to_both_bgs =
false,
1882 .name =
"Single4x3",
1884 .draws_to_both_bgs =
false,
1893 .name =
"RupeeFloor",
1895 .draws_to_both_bgs =
false,
1904 .name =
"Actual4x4",
1906 .draws_to_both_bgs =
false,
1915 .name =
"Waterfall47",
1917 .draws_to_both_bgs =
false,
1925 .name =
"Waterfall48",
1927 .draws_to_both_bgs =
false,
1936 .name =
"ClosedChestPlatform",
1938 .draws_to_both_bgs =
false,
1947 .name =
"MovingWallWest",
1949 .draws_to_both_bgs =
false,
1958 .name =
"MovingWallEast",
1960 .draws_to_both_bgs =
false,
1969 .name =
"OpenChestPlatform",
1971 .draws_to_both_bgs =
false,
1981 .name =
"DownwardsHasEdge1x1_1to16_plus23",
1985 int size = ctx.object.size_ & 0x0F;
1986 int count = size + 21;
1987 if (ctx.tiles.size() < 3)
1990 int tile_y = ctx.object.y_;
1994 ctx.target_bg, ctx.object.x_, tile_y, {0x00E3})) {
2000 for (
int s = 0; s < count; s++) {
2009 .draws_to_both_bgs =
false,
2021 .name =
"CustomObject",
2023 .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 kDamFloodGate
constexpr int kRupeeFloor
constexpr int kWaterfall47
constexpr int kClosedChestPlatform
constexpr int kHorizontalTurtleRockPipe
constexpr int kBigLightBeam
constexpr int kSolidWallDecor3x4
constexpr int kVerticalTurtleRockPipe
constexpr int kWaterHopStairsB
constexpr int kMovingWallWest
constexpr int kMovingWallEast
constexpr int kFloorLight
constexpr int kUtility6x3
constexpr int kCustomObject
constexpr int kOpenChestPlatform
constexpr int kUtility3x5
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)
bool IsSouthLowerStraightInterroomStairs(int16_t object_id)
bool IsStraightInterroomLower(int16_t object_id)
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)
bool IsStraightInterroomUpper(int16_t object_id)
const gfx::TileInfo & TileAtWrapped(std::span< const gfx::TileInfo > tiles, size_t index)
bool IsAutoStairsDualLayer(int16_t object_id)
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 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 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 DrawChestPlatformVerticalWall(const DrawContext &ctx)
Draw chest platform vertical wall section.
void DrawClosedChestPlatform(const DrawContext &ctx)
Draw closed chest platform (Type 1 object 0xC1)
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 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 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 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 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.