526 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
532 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
538 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
544 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
550 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
556 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
562 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
568 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
574 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
580 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
586 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
592 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
598 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
604 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
610 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
616 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
622 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
628 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
634 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
640 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
647 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
653 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
659 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
665 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
671 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
677 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
683 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
689 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
695 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
701 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
707 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
713 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
719 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
725 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
731 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
737 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
743 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
749 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
755 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
761 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
767 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
773 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
779 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
785 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
791 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
797 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
803 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
809 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
815 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
821 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
827 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
833 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
839 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
845 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
851 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
857 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
868 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
875 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
883 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
890 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
897 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
904 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
911 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
918 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
925 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
936 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
943 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
950 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
957 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
964 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
971 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
978 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
985 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
992 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
999 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1010 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1017 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1024 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1031 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1042 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1049 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1056 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1063 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1074 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1081 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1088 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1095 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1102 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1109 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1116 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1123 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1130 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1137 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1144 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1151 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1158 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1165 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1173 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1180 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1188 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1196 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1204 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1212 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1214 obj, bg, tiles, state);
1221 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1229 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1237 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1245 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1253 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1261 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1263 obj, bg, tiles, state);
1269 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1271 obj, bg, tiles, state);
1277 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1285 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1293 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1303 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1313 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1314 if (obj.
id_ == 0xFB1) {
1315 self->DrawBigChest(obj, bg, tiles, state);
1327 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1337 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1342 auto ensure_index = [
this](
size_t index) {
1346 std::span<const gfx::TileInfo> tiles,
1358 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1366 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1373 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1381 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1389 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1397 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1406 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1414 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1425 std::span<const gfx::TileInfo> tiles,
1450 LOG_DEBUG(
"ObjectDrawer",
"DrawDoor: idx=%d type=%d dir=%d pos=%d",
1451 door_index,
static_cast<int>(door.
type),
1455 LOG_DEBUG(
"ObjectDrawer",
"DrawDoor: SKIPPED - rom=%p loaded=%d gfx=%p",
1461 auto& bitmap = bg1.
bitmap();
1462 if (!bitmap.is_active() || bitmap.width() == 0) {
1464 "DrawDoor: SKIPPED - bitmap not active or zero width");
1474 int door_height = dims.height_tiles;
1476 LOG_DEBUG(
"ObjectDrawer",
"DrawDoor: tile_pos=(%d,%d) dims=%dx%d", tile_x,
1477 tile_y, door_width, door_height);
1479 constexpr int kRoomDrawObjectDataBase = 0x1B52;
1480 constexpr int kDoorwayReplacementDoorGfxBase = 0x1A02;
1481 constexpr int kExplodingWallTilemapPositionBase = 0x19DE;
1482 constexpr int kExplodingWallOpenReplacementType = 0x54;
1483 constexpr int kNorthCurtainClosedOffset = 0x078A;
1484 const auto& rom_data =
rom_->
data();
1487 int start_tile_x,
int start_tile_y,
1488 int width,
int height,
int tile_data_addr) {
1489 auto& bitmap = target.
bitmap();
1492 const int bitmap_width = bitmap.width();
1495 for (
int dx = 0; dx < width; dx++) {
1496 for (
int dy = 0; dy < height; dy++) {
1497 const int addr = tile_data_addr + (tile_idx * 2);
1498 const uint16_t tile_word = rom_data[addr] | (rom_data[addr + 1] << 8);
1500 const int pixel_x = (start_tile_x + dx) * 8;
1501 const int pixel_y = (start_tile_y + dy) * 8;
1507 const uint8_t priority = tile_info.over_ ? 1 : 0;
1508 const auto& bitmap_data = bitmap.vector();
1509 for (
int py = 0; py < 8; py++) {
1510 const int dest_y = pixel_y + py;
1511 if (dest_y < 0 || dest_y >= bitmap.height()) {
1514 for (
int px = 0; px < 8; px++) {
1515 const int dest_x = pixel_x + px;
1516 if (dest_x < 0 || dest_x >= bitmap_width) {
1519 const int dest_index = dest_y * bitmap_width + dest_x;
1520 if (dest_index >= 0 &&
1521 dest_index <
static_cast<int>(coverage_buffer.size())) {
1522 coverage_buffer[dest_index] = 1;
1524 if (dest_index <
static_cast<int>(bitmap_data.size()) &&
1525 bitmap_data[dest_index] != 255) {
1526 priority_buffer[dest_index] = priority;
1537 int start_tile_y,
int width,
int height,
1538 uint16_t tile_word) {
1539 auto& bitmap = target.
bitmap();
1542 const int bitmap_width = bitmap.width();
1545 for (
int dx = 0; dx < width; dx++) {
1546 for (
int dy = 0; dy < height; dy++) {
1547 const int pixel_x = (start_tile_x + dx) * 8;
1548 const int pixel_y = (start_tile_y + dy) * 8;
1554 const uint8_t priority = tile_info.over_ ? 1 : 0;
1555 const auto& bitmap_data = bitmap.vector();
1556 for (
int py = 0; py < 8; py++) {
1557 const int dest_y = pixel_y + py;
1558 if (dest_y < 0 || dest_y >= bitmap.height()) {
1561 for (
int px = 0; px < 8; px++) {
1562 const int dest_x = pixel_x + px;
1563 if (dest_x < 0 || dest_x >= bitmap_width) {
1566 const int dest_index = dest_y * bitmap_width + dest_x;
1567 if (dest_index >= 0 &&
1568 dest_index <
static_cast<int>(coverage_buffer.size())) {
1569 coverage_buffer[dest_index] = 1;
1571 if (dest_index <
static_cast<int>(bitmap_data.size()) &&
1572 bitmap_data[dest_index] != 255) {
1573 priority_buffer[dest_index] = priority;
1581 auto tilemap_offset_to_tile_coords = [](uint16_t offset) {
1582 return std::pair<int, int>{
static_cast<int>((offset % 0x80) / 2),
1583 static_cast<int>(offset / 0x80) - 4};
1585 const int position_index = std::min<int>(door.
position & 0x0F, 11);
1587 auto resolve_render_type = [](
DoorDirection render_direction,
1589 switch (render_type) {
1617 int start_tile_y,
DoorType render_type) ->
bool {
1618 int offset_table_addr = 0;
1619 switch (render_direction) {
1635 resolve_render_type(render_direction, render_type);
1636 const int render_type_value =
static_cast<int>(resolved_type);
1637 const int type_index = render_type_value / 2;
1638 const int table_entry_addr = offset_table_addr + (type_index * 2);
1639 if (table_entry_addr + 1 >=
static_cast<int>(
rom_->
size())) {
1643 const uint16_t tile_offset =
1644 rom_data[table_entry_addr] | (rom_data[table_entry_addr + 1] << 8);
1645 const int tile_data_addr = kRoomDrawObjectDataBase + tile_offset;
1647 const int data_size = dims.width_tiles * dims.height_tiles * 2;
1648 if (tile_data_addr < 0 ||
1649 tile_data_addr + data_size >
static_cast<int>(
rom_->
size())) {
1653 draw_from_object_data(target, start_tile_x, start_tile_y, dims.width_tiles,
1654 dims.height_tiles, tile_data_addr);
1663 "DrawDoor: closed exploding wall intentionally draws nothing");
1670 const int tile_data_addr =
1671 kRoomDrawObjectDataBase + kNorthCurtainClosedOffset;
1672 const int data_size = 16 * 2;
1673 if (tile_data_addr < 0 ||
1674 tile_data_addr + data_size >
static_cast<int>(
rom_->
size())) {
1679 draw_from_object_data(bg1, tile_x, tile_y, 4, 4,
1686 const int replacement_type_addr =
1687 kDoorwayReplacementDoorGfxBase +
static_cast<int>(door.
type);
1688 if (replacement_type_addr < 0 ||
1689 replacement_type_addr >=
static_cast<int>(
rom_->
size())) {
1695 const int replacement_type = rom_data[replacement_type_addr];
1696 const int table_entry_addr =
kDoorGfxUp + replacement_type;
1697 if (table_entry_addr < 0 ||
1698 table_entry_addr + 1 >=
static_cast<int>(
rom_->
size())) {
1704 const uint16_t tile_offset =
1705 rom_data[table_entry_addr] | (rom_data[table_entry_addr + 1] << 8);
1706 const int tile_data_addr = kRoomDrawObjectDataBase + tile_offset;
1707 const int data_size = 16 * 2;
1708 if (tile_data_addr < 0 ||
1709 tile_data_addr + data_size >
static_cast<int>(
rom_->
size())) {
1715 draw_from_object_data(bg1, tile_x, tile_y, 4, 4,
1722 const int position_index = std::min<int>(door.
position & 0x0F, 5);
1723 const int tilemap_entry_addr =
1724 kExplodingWallTilemapPositionBase + (position_index * 2);
1725 if (tilemap_entry_addr < 0 ||
1726 tilemap_entry_addr + 1 >=
static_cast<int>(
rom_->
size())) {
1732 const uint16_t tilemap_offset =
1733 rom_data[tilemap_entry_addr] | (rom_data[tilemap_entry_addr + 1] << 8);
1734 const auto explosion_tile_coords =
1735 tilemap_offset_to_tile_coords(tilemap_offset);
1736 const int explosion_tile_x = explosion_tile_coords.first;
1737 const int explosion_tile_y = explosion_tile_coords.second;
1739 auto draw_exploding_wall_segment = [&](
int table_entry_addr,
1740 int segment_tile_y) ->
bool {
1741 if (table_entry_addr < 0 ||
1742 table_entry_addr + 1 >=
static_cast<int>(
rom_->
size())) {
1746 const uint16_t tile_offset =
1747 rom_data[table_entry_addr] | (rom_data[table_entry_addr + 1] << 8);
1748 const int tile_data_addr = kRoomDrawObjectDataBase + tile_offset;
1749 constexpr int kFillWordIndex = 12;
1750 const int min_data_size = (kFillWordIndex + 1) * 2;
1751 if (tile_data_addr < 0 ||
1752 tile_data_addr + min_data_size >
static_cast<int>(
rom_->
size())) {
1756 draw_from_object_data(bg1, explosion_tile_x, segment_tile_y,
1757 2, 6, tile_data_addr);
1758 const uint16_t fill_word =
1759 rom_data[tile_data_addr + (kFillWordIndex * 2)] |
1760 (rom_data[tile_data_addr + (kFillWordIndex * 2) + 1] << 8);
1761 draw_repeated_tile(bg1, explosion_tile_x + 2, segment_tile_y,
1766 const int south_table_entry_addr =
1768 const int north_table_entry_addr =
1769 kDoorGfxUp + kExplodingWallOpenReplacementType;
1770 if (!draw_exploding_wall_segment(south_table_entry_addr,
1771 explosion_tile_y) ||
1772 !draw_exploding_wall_segment(north_table_entry_addr,
1773 explosion_tile_y + 6)) {
1791 const int counterpart_tile_x =
1793 const int counterpart_tile_y =
1795 (void)draw_table_door(bg1, counterpart_direction, counterpart_tile_x,
1796 counterpart_tile_y, door.
type);
1799 const bool drew_current =
1800 draw_table_door(bg1, door.
direction, tile_x, tile_y, door.
type);
1801 if (!drew_current) {
1803 "DrawDoor: INVALID ADDRESS - falling back to indicator");
1810 "DrawDoor: type=%s dir=%s pos=%d at tile(%d,%d) size=%dx%d",
1813 door.
position, tile_x, tile_y, door_width, door_height);