6#include "absl/strings/str_format.h"
21 : rom_(rom), room_id_(room_id), room_gfx_buffer_(room_gfx_buffer) {
32 return absl::FailedPreconditionError(
"ROM not loaded");
36 return absl::FailedPreconditionError(
"Draw routines not initialized");
40 auto mutable_obj =
const_cast<RoomObject&
>(object);
42 mutable_obj.EnsureTilesLoaded();
49 auto& target_bg = use_bg2 ? bg2 : bg1;
52 LOG_DEBUG(
"ObjectDrawer",
"Object 0x%03X layer=%d -> drawing to %s buffer",
53 object.id_,
static_cast<int>(
object.layer_),
54 use_bg2 ?
"BG2 (behind layout)" :
"BG1 (on top of layout)");
57 if (mutable_obj.tiles().empty()) {
58 LOG_DEBUG(
"ObjectDrawer",
"Object 0x%03X at (%d,%d) has NO TILES - skipping",
59 object.id_,
object.x_,
object.y_);
60 return absl::OkStatus();
65 int subtype =
object.size_ & 0x1F;
74 if (
object.all_bgs_) {
87 "Object 0x%03X at (%d,%d) size=%d -> routine=%d tiles=%zu",
88 object.id_,
object.x_,
object.y_,
object.size_, routine_id,
89 mutable_obj.tiles().size());
91 if (routine_id < 0 || routine_id >=
static_cast<int>(
draw_routines_.size())) {
93 "Object 0x%03X: NO ROUTINE (id=%d, max=%zu) - using fallback 1x1",
96 if (!mutable_obj.tiles().empty()) {
97 const auto& tile_info = mutable_obj.tiles()[0];
98 WriteTile8(target_bg,
object.x_,
object.y_, tile_info);
100 return absl::OkStatus();
112 draw_routines_[routine_id](
this, object, bg1, mutable_obj.tiles(), state);
113 draw_routines_[routine_id](
this, object, bg2, mutable_obj.tiles(), state);
126 bool is_pit_or_mask = (
object.id_ == 0xA4) ||
127 (
object.id_ >= 0x9B &&
object.id_ <= 0xA6) ||
128 (
object.id_ == 0xFE6) ||
129 (
object.id_ == 0xFBE ||
object.id_ == 0xFBF);
136 "Pit mask 0x%03X at (%d,%d) -> marking %dx%d pixels transparent in BG1",
137 object.id_,
object.x_,
object.y_, pixel_width, pixel_height);
142 if (layout_bg1 !=
nullptr) {
148 return absl::OkStatus();
157 absl::Status status = absl::OkStatus();
160 int to_bg1 = 0, to_bg2 = 0, both_bgs = 0;
162 for (
const auto&
object : objects) {
171 }
else if (use_bg2) {
177 auto s =
DrawObject(
object, bg1, bg2, palette_group, state, layout_bg1);
178 if (!s.ok() && status.ok()) {
183 LOG_DEBUG(
"ObjectDrawer",
"Buffer routing: to_BG1=%d, to_BG2=%d, BothBGs=%d",
184 to_bg1, to_bg2, both_bgs);
188 auto& bg1_bmp = bg1.
bitmap();
189 auto& bg2_bmp = bg2.
bitmap();
192 if (bg1_bmp.modified() && bg1_bmp.surface() &&
193 bg1_bmp.mutable_data().size() > 0) {
194 SDL_LockSurface(bg1_bmp.surface());
197 size_t surface_size = bg1_bmp.surface()->h * bg1_bmp.surface()->pitch;
198 size_t buffer_size = bg1_bmp.mutable_data().size();
200 if (surface_size >= buffer_size) {
203 memcpy(bg1_bmp.surface()->pixels, bg1_bmp.mutable_data().data(),
206 LOG_DEBUG(
"ObjectDrawer",
"BG1 Surface too small: surf=%zu buf=%zu", surface_size, buffer_size);
208 SDL_UnlockSurface(bg1_bmp.surface());
211 if (bg2_bmp.modified() && bg2_bmp.surface() &&
212 bg2_bmp.mutable_data().size() > 0) {
213 SDL_LockSurface(bg2_bmp.surface());
214 size_t surface_size = bg2_bmp.surface()->h * bg2_bmp.surface()->pitch;
215 size_t buffer_size = bg2_bmp.mutable_data().size();
217 if (surface_size >= buffer_size) {
218 memcpy(bg2_bmp.surface()->pixels, bg2_bmp.mutable_data().data(),
221 LOG_DEBUG(
"ObjectDrawer",
"BG2 Surface too small: surf=%zu buf=%zu", surface_size, buffer_size);
223 SDL_UnlockSurface(bg2_bmp.surface());
248 static constexpr int kBothBGRoutines[] = {
262 for (
int id : kBothBGRoutines) {
263 if (routine_id ==
id)
return true;
294 for (
int id = 0x01;
id <= 0x02;
id++) {
299 for (
int id = 0x03;
id <= 0x04;
id++) {
302 for (
int id = 0x05;
id <= 0x06;
id++) {
305 for (
int id = 0x07;
id <= 0x08;
id++) {
309 for (
int id = 0x0A;
id <= 0x0B;
id++) {
316 for (
int id : {0x0C, 0x0D, 0x10, 0x11, 0x14}) {
320 for (
int id : {0x0E, 0x0F, 0x12, 0x13}) {
325 for (
int id : {0x15, 0x18, 0x19, 0x1C, 0x1D, 0x20}) {
329 for (
int id : {0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F}) {
337 for (
int id = 0x23;
id <= 0x2E;
id++) {
367 for (
int id = 0x3F;
id <= 0x46;
id++) {
416 for (
int id = 0x61;
id <= 0x62;
id++) {
419 for (
int id = 0x63;
id <= 0x64;
id++) {
422 for (
int id = 0x65;
id <= 0x66;
id++) {
425 for (
int id = 0x67;
id <= 0x68;
id++) {
429 for (
int id = 0x6A;
id <= 0x6B;
id++) {
511 for (
int id = 0x97;
id <= 0x9F;
id++) {
581 for (
int id = 0xC5;
id <= 0xCA;
id++) {
625 for (
int id = 0xE0;
id <= 0xE8;
id++) {
629 for (
int id = 0xE9;
id <= 0xEF;
id++) {
634 for (
int id = 0xF0;
id <= 0xF7;
id++) {
638 for (
int id = 0xF9;
id <= 0xFD;
id++) {
645 for (
int id = 0x100;
id <= 0x107;
id++) {
648 for (
int id = 0x108;
id <= 0x10F;
id++) {
651 for (
int id = 0x110;
id <= 0x113;
id++) {
654 for (
int id = 0x114;
id <= 0x117;
id++) {
658 for (
int id = 0x118;
id <= 0x11B;
id++) {
699 for (
int id = 0x130;
id <= 0x133;
id++) {
734 for (
int id = 0xF83;
id <= 0xF89;
id++) {
737 for (
int id = 0xF8A;
id <= 0xF8C;
id++) {
766 for (
int id = 0xF9B;
id <= 0xF9D;
id++) {
771 for (
int id = 0xF9E;
id <= 0xFA1;
id++) {
775 for (
int id = 0xFA2;
id <= 0xFA5;
id++) {
779 for (
int id = 0xFA6;
id <= 0xFA9;
id++) {
803 for (
int id = 0xFB4;
id <= 0xFB9;
id++) {
813 for (
int id = 0xFBE;
id <= 0xFC6;
id++) {
832 for (
int id = 0xFCF;
id <= 0xFD3;
id++) {
840 for (
int id = 0xFD6;
id <= 0xFDA;
id++) {
858 for (
int id = 0xFE3;
id <= 0xFE5;
id++) {
901 for (
int id = 0xFFC;
id <= 0xFFE;
id++) {
914 std::span<const gfx::TileInfo> tiles,
921 std::span<const gfx::TileInfo> tiles,
928 std::span<const gfx::TileInfo> tiles,
935 std::span<const gfx::TileInfo> tiles,
942 std::span<const gfx::TileInfo> tiles,
949 std::span<const gfx::TileInfo> tiles,
956 std::span<const gfx::TileInfo> tiles,
963 std::span<const gfx::TileInfo> tiles,
970 std::span<const gfx::TileInfo> tiles,
977 std::span<const gfx::TileInfo> tiles,
984 std::span<const gfx::TileInfo> tiles,
991 std::span<const gfx::TileInfo> tiles,
998 std::span<const gfx::TileInfo> tiles,
1005 std::span<const gfx::TileInfo> tiles,
1012 std::span<const gfx::TileInfo> tiles,
1019 std::span<const gfx::TileInfo> tiles,
1026 std::span<const gfx::TileInfo> tiles,
1033 std::span<const gfx::TileInfo> tiles,
1040 std::span<const gfx::TileInfo> tiles,
1047 std::span<const gfx::TileInfo> tiles,
1055 std::span<const gfx::TileInfo> tiles,
1062 std::span<const gfx::TileInfo> tiles,
1069 std::span<const gfx::TileInfo> tiles,
1076 std::span<const gfx::TileInfo> tiles,
1083 std::span<const gfx::TileInfo> tiles,
1090 std::span<const gfx::TileInfo> tiles,
1097 std::span<const gfx::TileInfo> tiles,
1104 std::span<const gfx::TileInfo> tiles,
1111 std::span<const gfx::TileInfo> tiles,
1118 std::span<const gfx::TileInfo> tiles,
1125 std::span<const gfx::TileInfo> tiles,
1132 std::span<const gfx::TileInfo> tiles,
1139 std::span<const gfx::TileInfo> tiles,
1146 std::span<const gfx::TileInfo> tiles,
1153 std::span<const gfx::TileInfo> tiles,
1160 std::span<const gfx::TileInfo> tiles,
1167 std::span<const gfx::TileInfo> tiles,
1174 std::span<const gfx::TileInfo> tiles,
1181 std::span<const gfx::TileInfo> tiles,
1188 std::span<const gfx::TileInfo> tiles,
1195 std::span<const gfx::TileInfo> tiles,
1202 std::span<const gfx::TileInfo> tiles,
1209 std::span<const gfx::TileInfo> tiles,
1216 std::span<const gfx::TileInfo> tiles,
1223 std::span<const gfx::TileInfo> tiles,
1230 std::span<const gfx::TileInfo> tiles,
1237 std::span<const gfx::TileInfo> tiles,
1244 std::span<const gfx::TileInfo> tiles,
1251 std::span<const gfx::TileInfo> tiles,
1258 std::span<const gfx::TileInfo> tiles,
1265 std::span<const gfx::TileInfo> tiles,
1272 std::span<const gfx::TileInfo> tiles,
1279 std::span<const gfx::TileInfo> tiles,
1286 std::span<const gfx::TileInfo> tiles,
1293 std::span<const gfx::TileInfo> tiles,
1300 std::span<const gfx::TileInfo> tiles,
1314 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1323 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1333 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1342 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1351 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1360 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1369 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1378 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1387 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1398 std::span<const gfx::TileInfo> tiles,
1406 std::span<const gfx::TileInfo> tiles,
1414 std::span<const gfx::TileInfo> tiles,
1422 std::span<const gfx::TileInfo> tiles,
1430 std::span<const gfx::TileInfo> tiles,
1438 std::span<const gfx::TileInfo> tiles,
1446 std::span<const gfx::TileInfo> tiles,
1454 std::span<const gfx::TileInfo> tiles,
1462 std::span<const gfx::TileInfo> tiles,
1470 std::span<const gfx::TileInfo> tiles,
1482 std::span<const gfx::TileInfo> tiles,
1490 std::span<const gfx::TileInfo> tiles,
1498 std::span<const gfx::TileInfo> tiles,
1506 std::span<const gfx::TileInfo> tiles,
1518 std::span<const gfx::TileInfo> tiles,
1526 std::span<const gfx::TileInfo> tiles,
1534 std::span<const gfx::TileInfo> tiles,
1542 std::span<const gfx::TileInfo> tiles,
1556 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1565 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1574 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1583 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1592 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1601 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1610 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1619 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1628 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1637 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1646 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1655 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1664 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr};
1673 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr,
nullptr};
1684 DrawContext ctx{bg, obj, tiles, state,
nullptr, 0,
nullptr,
nullptr};
1798 int size = obj.
size_ & 0x0F;
1799 int count = (size + 1) * 2;
1801 if (tiles.size() < 5)
return;
1804 for (
int row = 0; row < 5; row++) {
1809 for (
int s = 0; s < count; s++) {
1810 int col_x = obj.
x_ + 1 + s;
1811 for (
int row = 0; row < 5; row++) {
1813 size_t tile_idx = std::min(
size_t(5 + row), tiles.size() - 1);
1814 self->
WriteTile8(bg, col_x, obj.
y_ + row, tiles[tile_idx]);
1819 int last_x = obj.
x_ + 1 + count;
1820 for (
int row = 0; row < 5; row++) {
1821 size_t tile_idx = std::min(
size_t(10 + row), tiles.size() - 1);
1822 self->
WriteTile8(bg, last_x, obj.
y_ + row, tiles[tile_idx]);
1832 int size = obj.
size_ & 0x0F;
1833 int count = (size + 1) * 2;
1835 if (tiles.size() < 3)
return;
1838 for (
int row = 0; row < 3; row++) {
1843 for (
int s = 0; s < count; s++) {
1844 int col_x = obj.
x_ + 1 + s;
1845 for (
int row = 0; row < 3; row++) {
1851 int last_x = obj.
x_ + 1 + count;
1852 for (
int row = 0; row < 3; row++) {
1853 size_t tile_idx = std::min(
size_t(3 + row), tiles.size() - 1);
1854 self->
WriteTile8(bg, last_x, obj.
y_ + row, tiles[tile_idx]);
1971 LOG_DEBUG(
"ObjectDrawer",
"DrawDoor: idx=%d type=%d dir=%d pos=%d",
1972 door_index,
static_cast<int>(door.
type),
1976 LOG_DEBUG(
"ObjectDrawer",
"DrawDoor: SKIPPED - rom=%p loaded=%d gfx=%p",
1981 auto& bitmap = bg1.
bitmap();
1982 if (!bitmap.is_active() || bitmap.width() == 0) {
1983 LOG_DEBUG(
"ObjectDrawer",
"DrawDoor: SKIPPED - bitmap not active or zero width");
1991 int door_height = dims.height_tiles;
1993 LOG_DEBUG(
"ObjectDrawer",
"DrawDoor: tile_pos=(%d,%d) dims=%dx%d",
1994 tile_x, tile_y, door_width, door_height);
2003 int offset_table_addr = 0;
2012 int type_value =
static_cast<int>(door.
type);
2013 int type_index = type_value / 2;
2016 int table_entry_addr = offset_table_addr + (type_index * 2);
2017 if (table_entry_addr + 1 >=
static_cast<int>(
rom_->
size())) {
2023 const auto& rom_data =
rom_->
data();
2024 uint16_t tile_offset = rom_data[table_entry_addr] |
2025 (rom_data[table_entry_addr + 1] << 8);
2028 constexpr int kRoomDrawObjectDataBase = 0x1B52;
2029 int tile_data_addr = kRoomDrawObjectDataBase + tile_offset;
2032 "DrawDoor: offset_table=0x%X type_idx=%d tile_offset=0x%X tile_addr=0x%X",
2033 offset_table_addr, type_index, tile_offset, tile_data_addr);
2036 int tiles_per_door = door_width * door_height;
2037 int data_size = tiles_per_door * 2;
2038 if (tile_data_addr < 0 || tile_data_addr + data_size >
static_cast<int>(
rom_->
size())) {
2039 LOG_DEBUG(
"ObjectDrawer",
"DrawDoor: INVALID ADDRESS - falling back to indicator");
2048 LOG_DEBUG(
"ObjectDrawer",
"DrawDoor: Reading %d tiles from 0x%X",
2049 tiles_per_door, tile_data_addr);
2052 int bitmap_width = bitmap.width();
2054 for (
int dx = 0; dx < door_width; dx++) {
2055 for (
int dy = 0; dy < door_height; dy++) {
2056 int addr = tile_data_addr + (tile_idx * 2);
2057 uint16_t tile_word = rom_data[addr] | (rom_data[addr + 1] << 8);
2060 int pixel_x = (tile_x + dx) * 8;
2061 int pixel_y = (tile_y + dy) * 8;
2064 LOG_DEBUG(
"ObjectDrawer",
"DrawDoor: tile[%d] word=0x%04X id=%d pal=%d pixel=(%d,%d)",
2065 tile_idx, tile_word, tile_info.id_, tile_info.palette_, pixel_x, pixel_y);
2071 uint8_t priority = tile_info.over_ ? 1 : 0;
2072 const auto& bitmap_data = bitmap.vector();
2073 for (
int py = 0; py < 8; py++) {
2074 int dest_y = pixel_y + py;
2075 if (dest_y < 0 || dest_y >= bitmap.height())
continue;
2076 for (
int px = 0; px < 8; px++) {
2077 int dest_x = pixel_x + px;
2078 if (dest_x < 0 || dest_x >= bitmap_width)
continue;
2079 int dest_index = dest_y * bitmap_width + dest_x;
2080 if (dest_index <
static_cast<int>(bitmap_data.size()) &&
2081 bitmap_data[dest_index] != 255) {
2082 priority_buffer[dest_index] = priority;
2092 "DrawDoor: type=%s dir=%s pos=%d at tile(%d,%d) size=%dx%d "
2093 "offset_table=0x%X tile_offset=0x%X tile_addr=0x%X",
2096 door.
position, tile_x, tile_y, door_width, door_height,
2097 offset_table_addr, tile_offset, tile_data_addr);
2101 int width,
int height,
DoorType type,
2169 int pixel_x = tile_x * 8;
2170 int pixel_y = tile_y * 8;
2171 int pixel_width = width * 8;
2172 int pixel_height = height * 8;
2174 int bitmap_width = bitmap.
width();
2175 int bitmap_height = bitmap.
height();
2178 for (
int py = 0; py < pixel_height; py++) {
2179 for (
int px = 0; px < pixel_width; px++) {
2180 int dest_x = pixel_x + px;
2181 int dest_y = pixel_y + py;
2183 if (dest_x >= 0 && dest_x < bitmap_width &&
2184 dest_y >= 0 && dest_y < bitmap_height) {
2186 bool is_border = (px < 2 || px >= pixel_width - 2 ||
2187 py < 2 || py >= pixel_height - 2);
2188 uint8_t final_color = is_border ? (color_idx + 5) : color_idx;
2190 int offset = (dest_y * bitmap_width) + dest_x;
2198 std::span<const gfx::TileInfo> tiles,
2205 bool is_open =
false;
2217 if (is_open && tiles.size() >= 8) {
2219 if (tiles.size() >= 8) {
2229 if (tiles.size() >= 4) {
2238 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2242 LOG_DEBUG(
"ObjectDrawer",
"DrawNothing for object 0x%02X (logic/invisible)", obj.
id_);
2247 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2251 int size = obj.
size_;
2256 bool is_ceiling = (obj.
id_ == 0x00 || obj.
id_ == 0xB8 || obj.
id_ == 0xB9);
2257 if (is_ceiling && tiles.size() >= 4) {
2258 LOG_DEBUG(
"ObjectDrawer",
"Ceiling Draw: obj=0x%02X pos=(%d,%d) size=%d tiles=%zu",
2259 obj.
id_, obj.
x_, obj.
y_, size, tiles.size());
2260 LOG_DEBUG(
"ObjectDrawer",
" Tile IDs: [%d, %d, %d, %d]",
2261 tiles[0].id_, tiles[1].id_, tiles[2].id_, tiles[3].id_);
2262 LOG_DEBUG(
"ObjectDrawer",
" Palettes: [%d, %d, %d, %d]",
2263 tiles[0].palette_, tiles[1].palette_, tiles[2].palette_, tiles[3].palette_);
2267 "DrawRightwards2x2: obj=%04X pos=(%d,%d) size=%d tiles=%zu",
2268 obj.
id_, obj.
x_, obj.
y_, size, tiles.size());
2270 for (
int s = 0; s < size; s++) {
2271 if (tiles.size() >= 4) {
2284 "DrawRightwards2x2: SKIPPING - tiles.size()=%zu < 4",
2292 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2296 int size = obj.
size_;
2300 LOG_DEBUG(
"ObjectDrawer",
"Wall Draw 2x4: obj=0x%03X pos=(%d,%d) size=%d tiles=%zu",
2301 obj.
id_, obj.
x_, obj.
y_, size, tiles.size());
2303 "DrawRightwards2x4: obj=%04X pos=(%d,%d) size=%d tiles=%zu",
2304 obj.
id_, obj.
x_, obj.
y_, size, tiles.size());
2306 for (
int s = 0; s < size; s++) {
2307 if (tiles.size() >= 8) {
2319 }
else if (tiles.size() >= 4) {
2331 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2335 int size = obj.
size_ & 0x0F;
2336 int count = size + 1;
2339 "DrawRightwards2x4_1to16: obj=%04X pos=(%d,%d) size=%d count=%d tiles=%zu",
2340 obj.
id_, obj.
x_, obj.
y_, size, count, tiles.size());
2342 for (
int s = 0; s < count; s++) {
2343 if (tiles.size() >= 8) {
2355 }
else if (tiles.size() >= 4) {
2367 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2375 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2378 int size = obj.
size_ & 0x0F;
2382 int count = size + 1;
2384 for (
int s = 0; s < count; s++) {
2385 if (tiles.size() >= 4) {
2398 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2402 int size = obj.
size_ & 0x0F;
2407 int count = size + 7;
2409 if (tiles.size() < 5)
return;
2411 for (
int s = 0; s < count; s++) {
2415 int tile_x = obj.
x_ + s;
2416 int tile_y = obj.
y_ - s;
2418 WriteTile8(bg, tile_x, tile_y + 0, tiles[0]);
2419 WriteTile8(bg, tile_x, tile_y + 1, tiles[1]);
2420 WriteTile8(bg, tile_x, tile_y + 2, tiles[2]);
2421 WriteTile8(bg, tile_x, tile_y + 3, tiles[3]);
2422 WriteTile8(bg, tile_x, tile_y + 4, tiles[4]);
2428 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2432 int size = obj.
size_ & 0x0F;
2437 int count = size + 7;
2439 if (tiles.size() < 5)
return;
2441 for (
int s = 0; s < count; s++) {
2445 int tile_x = obj.
x_ + s;
2446 int tile_y = obj.
y_ + s;
2448 WriteTile8(bg, tile_x, tile_y + 0, tiles[0]);
2449 WriteTile8(bg, tile_x, tile_y + 1, tiles[1]);
2450 WriteTile8(bg, tile_x, tile_y + 2, tiles[2]);
2451 WriteTile8(bg, tile_x, tile_y + 3, tiles[3]);
2452 WriteTile8(bg, tile_x, tile_y + 4, tiles[4]);
2458 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2464 int size = obj.
size_ & 0x0F;
2465 int count = size + 6;
2467 if (tiles.size() < 5)
return;
2469 for (
int s = 0; s < count; s++) {
2470 int tile_x = obj.
x_ + s;
2471 int tile_y = obj.
y_ - s;
2473 WriteTile8(bg, tile_x, tile_y + 0, tiles[0]);
2474 WriteTile8(bg, tile_x, tile_y + 1, tiles[1]);
2475 WriteTile8(bg, tile_x, tile_y + 2, tiles[2]);
2476 WriteTile8(bg, tile_x, tile_y + 3, tiles[3]);
2477 WriteTile8(bg, tile_x, tile_y + 4, tiles[4]);
2484 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2490 int size = obj.
size_ & 0x0F;
2491 int count = size + 6;
2493 if (tiles.size() < 5)
return;
2495 for (
int s = 0; s < count; s++) {
2496 int tile_x = obj.
x_ + s;
2497 int tile_y = obj.
y_ + s;
2499 WriteTile8(bg, tile_x, tile_y + 0, tiles[0]);
2500 WriteTile8(bg, tile_x, tile_y + 1, tiles[1]);
2501 WriteTile8(bg, tile_x, tile_y + 2, tiles[2]);
2502 WriteTile8(bg, tile_x, tile_y + 3, tiles[3]);
2503 WriteTile8(bg, tile_x, tile_y + 4, tiles[4]);
2510 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2518 if (tiles.size() >= 16) {
2521 for (
int xx = 0; xx < 4; xx++) {
2522 for (
int yy = 0; yy < 4; yy++) {
2526 }
else if (tiles.size() >= 8) {
2530 for (
int xx = 0; xx < 2; xx++) {
2531 for (
int yy = 0; yy < 4; yy++) {
2535 }
else if (tiles.size() >= 4) {
2538 for (
int xx = 0; xx < 2; xx++) {
2539 for (
int yy = 0; yy < 2; yy++) {
2548 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2550 int size = obj.
size_ & 0x0F;
2553 int count = (size * 2) + 1;
2555 for (
int s = 0; s < count; s++) {
2556 if (tiles.size() >= 2) {
2566 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2571 int size = obj.
size_ & 0x0F;
2572 int count = (size + 1) * 2;
2574 if (tiles.size() < 3)
return;
2583 for (
int s = 0; s < count; s++) {
2594 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2599 int size = obj.
size_ & 0x0F;
2600 int count = size + 1;
2602 if (tiles.size() < 3)
return;
2611 for (
int s = 0; s < count; s++) {
2622 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2624 int size = obj.
size_ & 0x0F;
2627 int count = size + 10;
2629 for (
int s = 0; s < count; s++) {
2630 if (tiles.size() >= 2) {
2640 const std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2642 int size = obj.
size_ & 0x0F;
2645 int count = size + 10;
2647 for (
int s = 0; s < count; s++) {
2648 if (tiles.size() >= 2) {
2657 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2660 if (tiles.size() >= 1) {
2668 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2670 int size = obj.
size_ & 0x0F;
2673 int count = size + 1;
2676 if (obj.
id_ == 0xBA && tiles.size() >= 16) {
2677 LOG_DEBUG(
"ObjectDrawer",
"Large Ceiling Draw: obj=0x%02X pos=(%d,%d) size=%d tiles=%zu",
2678 obj.
id_, obj.
x_, obj.
y_, size, tiles.size());
2679 LOG_DEBUG(
"ObjectDrawer",
" First 4 Tile IDs: [%d, %d, %d, %d]",
2680 tiles[0].id_, tiles[1].id_, tiles[2].id_, tiles[3].id_);
2681 LOG_DEBUG(
"ObjectDrawer",
" First 4 Palettes: [%d, %d, %d, %d]",
2682 tiles[0].palette_, tiles[1].palette_, tiles[2].palette_, tiles[3].palette_);
2685 for (
int s = 0; s < count; s++) {
2686 if (tiles.size() >= 16) {
2689 for (
int x = 0; x < 4; ++x) {
2690 for (
int y = 0; y < 4; ++y) {
2691 WriteTile8(bg, obj.
x_ + (s * 4) + x, obj.
y_ + y, tiles[x * 4 + y]);
2700 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2702 int size = obj.
size_ & 0x0F;
2705 int count = size + 4;
2707 for (
int s = 0; s < count; s++) {
2708 if (tiles.size() >= 1) {
2717 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2722 if (state && state->IsDoorSwitchActive(
room_id_)) {
2724 if (tiles.size() >= 2) {
2729 if (tiles.size() > tile_index) {
2736 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2738 int size = obj.
size_ & 0x0F;
2741 int count = size + 1;
2743 for (
int s = 0; s < count; s++) {
2744 if (tiles.size() >= 16) {
2746 for (
int x = 0; x < 4; ++x) {
2747 for (
int y = 0; y < 4; ++y) {
2748 WriteTile8(bg, obj.
x_ + (s * 6) + x, obj.
y_ + y, tiles[x * 4 + y]);
2757 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2760 int size = obj.
size_ & 0x0F;
2763 int count = size + 1;
2765 for (
int s = 0; s < count; s++) {
2766 if (tiles.size() >= 6) {
2768 for (
int x = 0; x < 2; ++x) {
2769 for (
int y = 0; y < 3; ++y) {
2770 WriteTile8(bg, obj.
x_ + (s * 4) + x, obj.
y_ + y, tiles[x * 3 + y]);
2779 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2784 int size = obj.
size_ & 0x0F;
2787 int count = size + 1;
2789 for (
int s = 0; s < count; s++) {
2790 if (tiles.size() >= 8) {
2793 for (
int x = 0; x < 2; ++x) {
2794 for (
int y = 0; y < 4; ++y) {
2795 WriteTile8(bg, obj.
x_ + (s * 4) + x, obj.
y_ + y, tiles[x * 4 + y]);
2804 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2809 int size = obj.
size_ & 0x0F;
2812 int count = size + 1;
2814 for (
int s = 0; s < count; s++) {
2815 if (tiles.size() >= 12) {
2818 for (
int x = 0; x < 4; ++x) {
2819 for (
int y = 0; y < 3; ++y) {
2820 WriteTile8(bg, obj.
x_ + (s * 8) + x, obj.
y_ + y, tiles[x * 3 + y]);
2829 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2832 int size = obj.
size_ & 0x0F;
2835 int count = size + 1;
2837 for (
int s = 0; s < count; s++) {
2838 if (tiles.size() >= 8) {
2840 for (
int x = 0; x < 4; ++x) {
2841 for (
int y = 0; y < 2; ++y) {
2842 WriteTile8(bg, obj.
x_ + (s * 6) + x, obj.
y_ + y, tiles[x * 2 + y]);
2851 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2853 int size = obj.
size_ & 0x0F;
2856 int count = size + 1;
2858 for (
int s = 0; s < count; s++) {
2859 if (tiles.size() >= 4) {
2875 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2880 int size = obj.
size_ & 0x0F;
2881 int count = size + 1;
2883 for (
int s = 0; s < count; s++) {
2884 if (tiles.size() >= 8) {
2902 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2907 int size = obj.
size_ & 0x0F;
2908 int count = size + 1;
2910 if (tiles.size() < 8)
return;
2912 for (
int s = 0; s < count; s++) {
2914 int base_x = obj.
x_ + (s * 12);
2915 for (
int row = 0; row < 8; row++) {
2923 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2927 int size = obj.
size_ & 0x0F;
2928 int count = size + 1;
2930 for (
int s = 0; s < count; s++) {
2931 if (tiles.size() >= 12) {
2932 int base_x = obj.
x_ + (s * 4);
2948 }
else if (tiles.size() >= 8) {
2950 int base_x = obj.
x_ + (s * 4);
2967 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2970 int size = obj.
size_ & 0x0F;
2971 int count = size + 2;
2973 for (
int s = 0; s < count; s++) {
2974 if (tiles.size() >= 1) {
2982 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
2985 int size = obj.
size_ & 0x0F;
2986 int count = size + 1;
2988 for (
int s = 0; s < count; s++) {
2989 if (tiles.size() >= 12) {
2990 int base_x = obj.
x_ + (s * 6);
3012 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3016 int size = obj.
size_ & 0x0F;
3017 int count = size + 1;
3019 for (
int s = 0; s < count; s++) {
3020 if (tiles.size() >= 16) {
3021 int base_x = obj.
x_ + (s * 6);
3023 for (
int col = 0; col < 4; col++) {
3024 for (
int row = 0; row < 4; row++) {
3025 int tile_idx = col * 4 + row;
3026 WriteTile8(bg, base_x + col, obj.
y_ + row, tiles[tile_idx]);
3035 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3043 int size = obj.
size_ & 0x0F;
3044 int middle_count = size + 2;
3046 if (tiles.size() < 15)
return;
3062 for (
int s = 0; s < middle_count; s++) {
3082 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3086 int size = obj.
size_ & 0x0F;
3087 int count = size + 1;
3089 for (
int s = 0; s < count; s++) {
3090 if (tiles.size() >= 4) {
3091 int base_x = obj.
x_ + (s * 4);
3107 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3110 int size = obj.
size_;
3114 for (
int s = 0; s < size; s++) {
3115 if (tiles.size() >= 4) {
3133 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3136 int size = obj.
size_;
3140 LOG_DEBUG(
"ObjectDrawer",
"Wall Draw 4x2 Vertical: obj=0x%03X pos=(%d,%d) size=%d tiles=%zu",
3141 obj.
id_, obj.
x_, obj.
y_, size, tiles.size());
3143 for (
int s = 0; s < size; s++) {
3144 if (tiles.size() >= 8) {
3156 }
else if (tiles.size() >= 4) {
3168 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3176 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3179 int size = obj.
size_ & 0x0F;
3182 int count = size + 1;
3184 for (
int s = 0; s < count; s++) {
3185 if (tiles.size() >= 8) {
3205 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3207 int size = obj.
size_ & 0x0F;
3210 int count = size + 1;
3212 for (
int s = 0; s < count; s++) {
3213 if (tiles.size() >= 4) {
3229 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3231 int size = obj.
size_ & 0x0F;
3234 int count = size + 2;
3236 for (
int s = 0; s < count; s++) {
3237 if (tiles.size() >= 1) {
3246 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3251 int size = obj.
size_ & 0x0F;
3252 int count = (size + 1) * 2;
3254 if (tiles.size() < 3)
return;
3256 int tile_y = obj.
y_;
3263 for (
int s = 0; s < count; s++) {
3274 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3276 int size = obj.
size_ & 0x0F;
3279 int count = size + 1;
3281 for (
int s = 0; s < count; s++) {
3282 if (tiles.size() >= 1) {
3291 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3293 int size = obj.
size_ & 0x0F;
3296 int count = size + 10;
3298 for (
int s = 0; s < count; s++) {
3299 if (tiles.size() >= 2) {
3309 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3311 int size = obj.
size_ & 0x0F;
3314 int count = size + 10;
3316 for (
int s = 0; s < count; s++) {
3317 if (tiles.size() >= 2) {
3329 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3333 int size = obj.
size_ & 0x0F;
3334 int count = size + 1;
3336 for (
int s = 0; s < count; s++) {
3337 if (tiles.size() >= 16) {
3339 for (
int col = 0; col < 4; col++) {
3340 for (
int row = 0; row < 4; row++) {
3341 int tile_idx = col * 4 + row;
3342 WriteTile8(bg, obj.
x_ + col, obj.
y_ + (s * 4) + row, tiles[tile_idx]);
3351 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3354 int size = obj.
size_ & 0x0F;
3355 int count = size + 4;
3357 for (
int s = 0; s < count; s++) {
3358 if (tiles.size() >= 1) {
3366 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3370 int size = obj.
size_ & 0x0F;
3371 int count = size + 1;
3373 for (
int s = 0; s < count; s++) {
3374 if (tiles.size() >= 16) {
3376 for (
int col = 0; col < 4; col++) {
3377 for (
int row = 0; row < 4; row++) {
3378 int tile_idx = col * 4 + row;
3379 WriteTile8(bg, obj.
x_ + col, obj.
y_ + (s * 6) + row, tiles[tile_idx]);
3388 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3392 int size = obj.
size_ & 0x0F;
3393 int count = size + 1;
3395 for (
int s = 0; s < count; s++) {
3396 if (tiles.size() >= 8) {
3398 for (
int col = 0; col < 2; col++) {
3399 for (
int row = 0; row < 4; row++) {
3400 int tile_idx = col * 4 + row;
3401 WriteTile8(bg, obj.
x_ + col, obj.
y_ + (s * 6) + row, tiles[tile_idx]);
3410 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3414 int size = obj.
size_ & 0x0F;
3415 int count = size + 1;
3417 for (
int s = 0; s < count; s++) {
3418 if (tiles.size() >= 12) {
3420 for (
int col = 0; col < 3; col++) {
3421 for (
int row = 0; row < 4; row++) {
3422 int tile_idx = col * 4 + row;
3423 WriteTile8(bg, obj.
x_ + col, obj.
y_ + (s * 8) + row, tiles[tile_idx]);
3432 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3436 int size = obj.
size_ & 0x0F;
3437 int count = size + 1;
3439 for (
int s = 0; s < count; s++) {
3440 if (tiles.size() >= 4) {
3442 for (
int col = 0; col < 2; col++) {
3443 for (
int row = 0; row < 2; row++) {
3444 int tile_idx = col * 2 + row;
3445 WriteTile8(bg, obj.
x_ + col, obj.
y_ + (s * 14) + row, tiles[tile_idx]);
3454 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3457 int size = obj.
size_ & 0x0F;
3458 int count = size + 2;
3460 for (
int s = 0; s < count; s++) {
3461 if (tiles.size() >= 1) {
3469 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3473 int size = obj.
size_ & 0x0F;
3474 int count = size + 1;
3477 if (obj.
id_ == 0x80 && tiles.size() >= 8) {
3478 LOG_DEBUG(
"ObjectDrawer",
"Vertical Ceiling Draw: obj=0x%02X pos=(%d,%d) size=%d tiles=%zu",
3479 obj.
id_, obj.
x_, obj.
y_, size, tiles.size());
3480 LOG_DEBUG(
"ObjectDrawer",
" Tile IDs: [%d, %d, %d, %d, %d, %d, %d, %d]",
3481 tiles[0].id_, tiles[1].id_, tiles[2].id_, tiles[3].id_,
3482 tiles[4].id_, tiles[5].id_, tiles[6].id_, tiles[7].id_);
3483 LOG_DEBUG(
"ObjectDrawer",
" Palettes: [%d, %d, %d, %d, %d, %d, %d, %d]",
3484 tiles[0].palette_, tiles[1].palette_, tiles[2].palette_, tiles[3].palette_,
3485 tiles[4].palette_, tiles[5].palette_, tiles[6].palette_, tiles[7].palette_);
3488 for (
int s = 0; s < count; s++) {
3489 if (tiles.size() >= 8) {
3491 for (
int col = 0; col < 2; col++) {
3492 for (
int row = 0; row < 4; row++) {
3493 int tile_idx = col * 4 + row;
3494 WriteTile8(bg, obj.
x_ + col, obj.
y_ + (s * 10) + row, tiles[tile_idx]);
3507 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3510 int size = obj.
size_ & 0x0F;
3511 int count = size + 1;
3513 for (
int s = 0; s < count; s++) {
3514 if (tiles.size() >= 12) {
3516 for (
int col = 0; col < 3; col++) {
3517 for (
int row = 0; row < 4; row++) {
3518 int tile_idx = col * 4 + row;
3519 WriteTile8(bg, obj.
x_ + col, obj.
y_ + (s * 6) + row, tiles[tile_idx]);
3528 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3536 int size = obj.
size_ & 0x0F;
3537 int middle_count = size + 1;
3539 if (tiles.size() < 12)
return;
3553 for (
int s = 0; s < middle_count; s++) {
3572 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3575 int size = obj.
size_ & 0x0F;
3576 int count = size + 1;
3578 for (
int s = 0; s < count; s++) {
3579 if (tiles.size() >= 4) {
3580 int base_y = obj.
y_ + (s * 4);
3592 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3596 int size = obj.
size_ & 0x0F;
3597 int count = size + 1;
3599 for (
int s = 0; s < count; s++) {
3600 if (tiles.size() >= 18) {
3602 for (
int col = 0; col < 3; col++) {
3603 for (
int row = 0; row < 6; row++) {
3604 int tile_idx = col * 6 + row;
3605 WriteTile8(bg, obj.
x_ + col, obj.
y_ + (s * 6) + row, tiles[tile_idx]);
3614 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3617 int size = obj.
size_ & 0x0F;
3618 int count = size + 1;
3620 for (
int s = 0; s < count; s++) {
3621 if (tiles.size() >= 6) {
3623 for (
int col = 0; col < 2; col++) {
3624 for (
int row = 0; row < 3; row++) {
3625 int tile_idx = col * 3 + row;
3626 WriteTile8(bg, obj.
x_ + col, obj.
y_ + (s * 3) + row, tiles[tile_idx]);
3635 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3638 int size = obj.
size_ & 0x0F;
3639 int count = size + 1;
3641 for (
int s = 0; s < count; s++) {
3642 if (tiles.size() >= 4) {
3643 int base_y = obj.
y_ + (s * 2);
3655 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3658 int size = obj.
size_ & 0x0F;
3659 int count = size + 1;
3661 for (
int s = 0; s < count; s++) {
3662 if (tiles.size() >= 4) {
3663 int base_y = obj.
y_ + (s * 2);
3675 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3678 int size = obj.
size_ & 0x0F;
3679 int count = size + 8;
3681 for (
int s = 0; s < count; s++) {
3682 if (tiles.size() >= 1) {
3690 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3693 int size = obj.
size_ & 0x0F;
3694 int count = size + 1;
3696 for (
int s = 0; s < count; s++) {
3697 if (tiles.size() >= 4) {
3698 int base_x = obj.
x_ + (s * 2);
3710 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3713 int size = obj.
size_ & 0x0F;
3714 int count = size + 1;
3716 for (
int s = 0; s < count; s++) {
3717 if (tiles.size() >= 4) {
3718 int base_x = obj.
x_ + (s * 2);
3734 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3738 int count = (obj.
size_ & 0x0F) + 4;
3740 if (tiles.empty()) {
3741 LOG_DEBUG(
"ObjectDrawer",
"DiagonalCeilingTopLeft: No tiles for obj 0x%02X", obj.
id_);
3746 "DiagonalCeilingTopLeft: obj=0x%02X pos=(%d,%d) size=%d count=%d",
3750 int tiles_in_row = count;
3751 for (
int row = 0; row < count && tiles_in_row > 0; row++) {
3752 for (
int col = 0; col < tiles_in_row; col++) {
3761 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3765 int count = (obj.
size_ & 0x0F) + 4;
3767 if (tiles.empty())
return;
3770 for (
int row = 0; row < count; row++) {
3771 int tiles_in_row = row + 1;
3772 for (
int col = 0; col < tiles_in_row; col++) {
3780 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3784 int count = (obj.
size_ & 0x0F) + 4;
3786 if (tiles.empty())
return;
3789 int tiles_in_row = count;
3790 for (
int row = 0; row < count && tiles_in_row > 0; row++) {
3791 for (
int col = 0; col < tiles_in_row; col++) {
3800 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
3804 int count = (obj.
size_ & 0x0F) + 4;
3806 if (tiles.empty())
return;
3809 int tiles_in_row = count;
3810 for (
int row = 0; row < count && tiles_in_row > 0; row++) {
3811 for (
int col = 0; col < tiles_in_row; col++) {
3824 std::span<const gfx::TileInfo> tiles) {
3840 if (tiles.size() < 16)
return;
3843 int width = (obj.
size_ & 0x0F) + 4;
3844 int height = ((obj.
size_ >> 4) & 0x0F) + 1;
3847 "DrawClosedChestPlatform: obj=0x%03X pos=(%d,%d) size=0x%02X width=%d height=%d",
3852 size_t tile_idx = 0;
3853 for (
int row = 0; row < height * 3; ++row) {
3854 for (
int col = 0; col < width * 2; ++col) {
3855 WriteTile8(bg, obj.
x_ + col, obj.
y_ + row, tiles[tile_idx % tiles.size()]);
3863 std::span<const gfx::TileInfo> tiles) {
3866 if (tiles.size() < 6)
return;
3868 int count = ((obj.
size_ >> 4) & 0x0F) + 4;
3871 for (
int row = 0; row < count; ++row) {
3872 for (
int col = 0; col < 3; ++col) {
3873 size_t tile_idx = (row * 3 + col) % tiles.size();
3881 std::span<const gfx::TileInfo> tiles) {
3884 if (tiles.size() < 6)
return;
3886 int count = ((obj.
size_ >> 4) & 0x0F) + 4;
3888 for (
int row = 0; row < count; ++row) {
3889 for (
int col = 0; col < 3; ++col) {
3890 size_t tile_idx = (row * 3 + col) % tiles.size();
3898 std::span<const gfx::TileInfo> tiles) {
3914 if (tiles.size() < 8)
return;
3917 int width = (obj.
size_ & 0x0F) + 1;
3920 int segments = ((obj.
size_ >> 4) & 0x0F) * 2 + 5;
3923 "DrawOpenChestPlatform: obj=0x%03X pos=(%d,%d) size=0x%02X width=%d segments=%d",
3931 int tile_offset = 0;
3932 for (
int seg = 0; seg < segments; ++seg) {
3933 for (
int col = 0; col < width; ++col) {
3934 size_t tile_idx = tile_offset % tiles.size();
3943 for (
int col = 0; col < width; ++col) {
3944 size_t tile_idx = tile_offset % tiles.size();
3945 WriteTile8(bg, obj.
x_ + col, obj.
y_ + segments, tiles[tile_idx]);
3949 for (
int col = 0; col < width; ++col) {
3950 size_t tile_idx = tile_offset % tiles.size();
3951 WriteTile8(bg, obj.
x_ + col, obj.
y_ + segments + 1, tiles[tile_idx]);
3961 int tile_y,
int pixel_width,
3963 auto& bitmap = bg1.
bitmap();
3964 if (!bitmap.is_active() || bitmap.width() == 0) {
3965 LOG_DEBUG(
"ObjectDrawer",
"MarkBG1Transparent: Bitmap not ready, skipping");
3969 int start_px = tile_x * 8;
3970 int start_py = tile_y * 8;
3971 int canvas_width = bitmap.width();
3972 int canvas_height = bitmap.height();
3973 auto& data = bitmap.mutable_data();
3975 int pixels_marked = 0;
3979 for (
int py = start_py; py < start_py + pixel_height && py < canvas_height;
3981 if (py < 0)
continue;
3982 for (
int px = start_px; px < start_px + pixel_width && px < canvas_width;
3984 if (px < 0)
continue;
3985 int idx = py * canvas_width + px;
3986 if (idx >= 0 && idx <
static_cast<int>(data.size())) {
3992 bitmap.set_modified(
true);
3995 "MarkBG1Transparent: Marked %d pixels at tile(%d,%d) pixel(%d,%d) size(%d,%d)",
3996 pixels_marked, tile_x, tile_y, start_px, start_py, pixel_width, pixel_height);
4002 auto& bitmap = bg.
bitmap();
4003 if (!bitmap.is_active() || bitmap.width() == 0) {
4013 LOG_DEBUG(
"ObjectDrawer",
"ERROR: No graphics data available");
4022 uint8_t priority = tile_info.
over_ ? 1 : 0;
4023 int pixel_x = tile_x * 8;
4024 int pixel_y = tile_y * 8;
4026 int width = bitmap.width();
4029 const auto& bitmap_data = bitmap.vector();
4030 for (
int py = 0; py < 8; py++) {
4031 int dest_y = pixel_y + py;
4032 if (dest_y < 0 || dest_y >= bitmap.height())
continue;
4034 for (
int px = 0; px < 8; px++) {
4035 int dest_x = pixel_x + px;
4036 if (dest_x < 0 || dest_x >= width)
continue;
4038 int dest_index = dest_y * width + dest_x;
4041 if (dest_index <
static_cast<int>(bitmap_data.size()) &&
4042 bitmap_data[dest_index] != 255) {
4043 priority_buffer[dest_index] = priority;
4050 return tile_x >= 0 && tile_x < kMaxTilesX && tile_y >= 0 &&
4056 int pixel_y,
const uint8_t* tiledata) {
4059 if (!tiledata)
return;
4063 LOG_DEBUG(
"ObjectDrawer",
"ERROR: Invalid bitmap - active=%d, size=%dx%d",
4072 constexpr int kGfxBufferSize = 0x10000;
4073 constexpr int kMaxTileRow = 63;
4075 int tile_col = tile_info.
id_ % 16;
4076 int tile_row = tile_info.
id_ / 16;
4079 if (tile_row > kMaxTileRow) {
4080 LOG_DEBUG(
"ObjectDrawer",
"Tile ID 0x%03X out of bounds (row %d > %d)",
4081 tile_info.
id_, tile_row, kMaxTileRow);
4085 int tile_base_x = tile_col * 8;
4086 int tile_base_y = tile_row * 1024;
4089 static int draw_debug_count = 0;
4090 if (draw_debug_count < 5) {
4091 int sample_index = tile_base_y + tile_base_x;
4092 LOG_DEBUG(
"ObjectDrawer",
"DrawTile: id=%d (col=%d,row=%d) gfx_offset=%d (0x%04X)",
4093 tile_info.
id_, tile_col, tile_row, sample_index, sample_index);
4106 uint8_t pal = tile_info.
palette_ & 0x07;
4107 uint8_t palette_offset;
4108 if (pal >= 2 && pal <= 7) {
4110 palette_offset = (pal - 2) * 16;
4117 bool any_pixels_written =
false;
4119 for (
int py = 0; py < 8; py++) {
4123 for (
int px = 0; px < 8; px++) {
4129 int src_index = (src_row * 128) + src_col + tile_base_x + tile_base_y;
4130 uint8_t pixel = tiledata[src_index];
4135 uint8_t final_color = pixel + palette_offset;
4136 int dest_x = pixel_x + px;
4137 int dest_y = pixel_y + py;
4139 if (dest_x >= 0 && dest_x < bitmap.
width() &&
4140 dest_y >= 0 && dest_y < bitmap.
height()) {
4141 int dest_index = dest_y * bitmap.
width() + dest_x;
4142 if (dest_index >= 0 &&
4143 dest_index <
static_cast<int>(bitmap.
mutable_data().size())) {
4145 any_pixels_written =
true;
4153 if (any_pixels_written) {
4164 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
4177 if (tiles.empty())
return;
4179 int length = (obj.
size_ & 0x0F) + 1;
4180 int obj_subid = obj.
id_ & 0x0F;
4184 switch (obj_subid) {
4185 case 0x03: dx = 1; dy = 0;
break;
4186 case 0x04: dx = 0; dy = 1;
break;
4187 case 0x05: dx = 1; dy = 1;
break;
4188 case 0x06: dx = -1; dy = 1;
break;
4189 case 0x07: dx = 1; dy = 0;
break;
4190 case 0x08: dx = 0; dy = 1;
break;
4191 case 0x09: dx = 1; dy = 1;
break;
4192 case 0x0A: dx = 1; dy = 0;
break;
4193 case 0x0B: dx = 0; dy = 1;
break;
4194 case 0x0C: dx = 1; dy = 1;
break;
4195 case 0x0E: dx = 1; dy = 0;
break;
4196 case 0x0F: dx = 0; dy = 1;
break;
4197 default: dx = 1; dy = 0;
break;
4201 for (
int i = 0; i < length; ++i) {
4202 int tile_idx = i % tiles.size();
4203 WriteTile8(bg, obj.
x_ + (i * dx), obj.
y_ + (i * dy), tiles[tile_idx]);
4209 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
4214 if (tiles.size() >= 4) {
4224 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
4227 if (tiles.size() >= 16) {
4229 }
else if (tiles.size() >= 8) {
4232 for (
int xx = 0; xx < 2; xx++) {
4233 for (
int yy = 0; yy < 4; yy++) {
4237 }
else if (tiles.size() >= 4) {
4245 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
4249 if (tiles.size() >= 16) {
4251 }
else if (tiles.size() >= 12) {
4254 for (
int xx = 0; xx < 3; xx++) {
4255 for (
int yy = 0; yy < 4; yy++) {
4259 }
else if (tiles.size() >= 8) {
4262 for (
int xx = 0; xx < 2; xx++) {
4263 for (
int yy = 0; yy < 4; yy++) {
4267 }
else if (tiles.size() >= 4) {
4274 std::span<const gfx::TileInfo> tiles, [[maybe_unused]]
const DungeonState* state) {
4278 if (tiles.size() >= 16) {
4280 }
else if (tiles.size() >= 12) {
4283 for (
int xx = 0; xx < 4; xx++) {
4284 for (
int yy = 0; yy < 3; yy++) {
4288 }
else if (tiles.size() >= 8) {
4291 for (
int xx = 0; xx < 2; xx++) {
4292 for (
int yy = 0; yy < 4; yy++) {
4296 }
else if (tiles.size() >= 4) {
4303 std::span<const gfx::TileInfo> tiles,
4304 int width,
int height) {
4306 if (tiles.size() >=
static_cast<size_t>(width * height)) {
4307 for (
int y = 0; y < height; ++y) {
4308 for (
int x = 0; x < width; ++x) {
4321 std::span<const gfx::TileInfo> tiles,
4325 constexpr int kWidth = 4;
4326 constexpr int kHeight = 5;
4328 if (tiles.size() >= kWidth * kHeight) {
4331 for (
int x = 0; x < kWidth && tid < static_cast<int>(tiles.size()); ++x) {
4332 for (
int y = 0; y < kHeight && tid < static_cast<int>(tiles.size()); ++y) {
4344 std::span<const gfx::TileInfo> tiles,
4348 constexpr int kWidth = 3;
4349 constexpr int kHeight = 6;
4351 if (tiles.size() >= kWidth * kHeight) {
4353 for (
int x = 0; x < kWidth && tid < static_cast<int>(tiles.size()); ++x) {
4354 for (
int y = 0; y < kHeight && tid < static_cast<int>(tiles.size()); ++y) {
4366 std::span<const gfx::TileInfo> tiles,
4370 constexpr int kWidth = 6;
4371 constexpr int kHeight = 3;
4373 if (tiles.size() >= kWidth * kHeight) {
4375 for (
int y = 0; y < kHeight && tid < static_cast<int>(tiles.size()); ++y) {
4376 for (
int x = 0; x < kWidth && tid < static_cast<int>(tiles.size()); ++x) {
4388 std::span<const gfx::TileInfo> tiles,
4392 constexpr int kWidth = 3;
4393 constexpr int kHeight = 5;
4395 if (tiles.size() >= kWidth * kHeight) {
4397 for (
int x = 0; x < kWidth && tid < static_cast<int>(tiles.size()); ++x) {
4398 for (
int y = 0; y < kHeight && tid < static_cast<int>(tiles.size()); ++y) {
4414 std::span<const gfx::TileInfo> tiles,
4418 constexpr int kWidth = 2;
4419 constexpr int kHeight = 6;
4421 if (tiles.size() >= kWidth * kHeight) {
4423 for (
int x = 0; x < kWidth && tid < static_cast<int>(tiles.size()); ++x) {
4424 for (
int y = 0; y < kHeight && tid < static_cast<int>(tiles.size()); ++y) {
4428 }
else if (tiles.size() >= 4) {
4436 std::span<const gfx::TileInfo> tiles,
4440 constexpr int kWidth = 6;
4441 constexpr int kHeight = 2;
4443 if (tiles.size() >= kWidth * kHeight) {
4445 for (
int y = 0; y < kHeight && tid < static_cast<int>(tiles.size()); ++y) {
4446 for (
int x = 0; x < kWidth && tid < static_cast<int>(tiles.size()); ++x) {
4450 }
else if (tiles.size() >= 4) {
4458 std::span<const gfx::TileInfo> tiles,
4463 constexpr int kWidth = 4;
4464 constexpr int kHeight = 4;
4466 if (tiles.size() >= kWidth * kHeight) {
4468 for (
int y = 0; y < kHeight && tid < static_cast<int>(tiles.size()); ++y) {
4469 for (
int x = 0; x < kWidth && tid < static_cast<int>(tiles.size()); ++x) {
4481 std::span<const gfx::TileInfo> tiles,
4485 constexpr int kWidth = 6;
4486 constexpr int kHeight = 6;
4488 if (tiles.size() >= kWidth * kHeight) {
4490 for (
int y = 0; y < kHeight && tid < static_cast<int>(tiles.size()); ++y) {
4491 for (
int x = 0; x < kWidth && tid < static_cast<int>(tiles.size()); ++x) {
4503 std::span<const gfx::TileInfo> tiles,
4513 std::span<const gfx::TileInfo> tiles,
4517 constexpr int kWidth = 3;
4518 constexpr int kHeight = 4;
4520 if (tiles.size() >= kWidth * kHeight) {
4522 for (
int x = 0; x < kWidth && tid < static_cast<int>(tiles.size()); ++x) {
4523 for (
int y = 0; y < kHeight && tid < static_cast<int>(tiles.size()); ++y) {
4535 std::span<const gfx::TileInfo> tiles,
4547 constexpr int kWidth = 3;
4548 constexpr int kSectionHeight = 3;
4550 if (tiles.size() >= 18) {
4553 for (
int x = 0; x < kWidth; ++x) {
4554 for (
int y = 0; y < kSectionHeight; ++y) {
4560 for (
int x = 0; x < kWidth; ++x) {
4561 for (
int y = 0; y < kSectionHeight; ++y) {
4562 WriteTile8(bg, obj.
x_ + x, obj.
y_ + kSectionHeight + y, tiles[tid++]);
4565 }
else if (tiles.size() >= 9) {
4568 for (
int x = 0; x < kWidth; ++x) {
4569 for (
int y = 0; y < kSectionHeight; ++y) {
4581 std::span<const gfx::TileInfo> tiles,
4587 if (tiles.size() >= 4) {
4597 std::span<const gfx::TileInfo> tiles,
4606 int num_tiles =
static_cast<int>(tiles.size());
4607 if (num_tiles == 0)
return;
4609 for (
int x = 0; x < 8; ++x) {
4610 for (
int y = 0; y < 8; ++y) {
4620 std::span<const gfx::TileInfo> tiles,
4626 if (tiles.size() >= 12) {
4628 for (
int x = 0; x < 4; ++x) {
4629 for (
int y = 0; y < 3; ++y) {
4638 std::span<const gfx::TileInfo> tiles,
4651 if (tiles.size() < 2)
return;
4654 for (
int col = 0; col < 3; ++col) {
4655 int x = obj.
x_ + (col * 2);
4680 std::span<const gfx::TileInfo> tiles,
4687 if (tiles.size() < 16)
return;
4690 for (
int x = 0; x < 4; ++x) {
4691 for (
int y = 0; y < 4; ++y) {
4699 std::span<const gfx::TileInfo> tiles,
4716 constexpr int kBlockSize = 4;
4718 if (tiles.size() >= 32) {
4721 for (
int y = 0; y < kBlockSize; ++y) {
4722 for (
int x = 0; x < kBlockSize; ++x) {
4729 for (
int y = 0; y < kBlockSize; ++y) {
4730 for (
int x = 0; x < kBlockSize; ++x) {
4731 WriteTile8(bg, obj.
x_ + x, obj.
y_ + kBlockSize + y, tiles[tid++]);
4737 for (
int y = 0; y < kBlockSize; ++y) {
4738 for (
int x = 0; x < kBlockSize; ++x) {
4739 WriteTile8(bg, obj.
x_ + x + 4, obj.
y_ + kBlockSize + y, tiles[tid++]);
4742 }
else if (tiles.size() >= 16) {
4745 for (
int y = 0; y < kBlockSize; ++y) {
4746 for (
int x = 0; x < kBlockSize; ++x) {
4769 int size =
object.size_;
4773 switch (routine_id) {
4779 if (routine_id == 0 || routine_id == 7) {
4780 if (size == 0) size = 32;
4783 if (size == 0) size = 16;
4786 if (routine_id == 0 || routine_id == 4) {
4800 int effective_size = (size == 0) ? 26 : (size & 0x0F);
4802 width = effective_size * 16;
4811 int count = size + 1;
4826 int count = size + 7;
4828 height = (count + 4) * 8;
4838 int count = size + 6;
4840 height = (count + 4) * 8;
4847 int effective_size = (size == 0) ? 26 : (size & 0x0F);
4850 height = effective_size * 16;
4858 int count = size + 1;
4860 height = count * 16;
4871 height = 16 + size * 16;
4878 int count = (size & 0x0F) + 1;
4894 int tile_count =
object.tiles().size();
4895 if (tile_count >= 16) {
4896 width = height = 32;
4898 width = height = 16;
4907 int count = (size * 2) + 1;
4918 int count = (size + 1) * 2;
4919 width = (count + 2) * 8;
4928 int count = size + 1;
4929 width = (count + 2) * 8;
4937 width = (size + 4) * 8;
4945 width = 8 + size * 8;
4959 int count = size + 1;
4961 width = ((count - 1) * 6 + 4) * 8;
4971 int count = size + 1;
4973 width = ((count - 1) * 4 + 2) * 8;
4983 int count = size + 1;
4985 width = ((count - 1) * 4 + 2) * 8;
4995 int count = size + 1;
4997 width = ((count - 1) * 8 + 4) * 8;
5007 int count = size + 1;
5009 width = ((count - 1) * 6 + 4) * 8;
5018 int count = size + 1;
5020 width = ((count - 1) * 14 + 2) * 8;
5028 width = 8 + size * 8;
5041 int count = size + 1;
5042 width = count * 4 * 8;
5051 int count = size + 1;
5052 width = ((count - 1) * 12 + 1) * 8;
5061 int count = size + 1;
5062 width = count * 4 * 8;
5071 int count = size + 1;
5073 height = count * 4 * 8;
5081 height = (size + 4) * 8;
5088 int count = size + 1;
5090 height = ((count - 1) * 6 + 4) * 8;
5097 int count = size + 1;
5099 height = ((count - 1) * 6 + 4) * 8;
5106 int count = size + 1;
5108 height = ((count - 1) * 6 + 4) * 8;
5115 int count = size + 1;
5117 height = ((count - 1) * 14 + 2) * 8;
5125 height = (size + 2) * 8;
5132 int count = size + 1;
5134 height = ((count - 1) * 12 + 4) * 8;
5141 width = (size + 2) * 8;
5149 int count = size + 1;
5150 width = ((count - 1) * 6 + 4) * 8;
5158 int count = size + 1;
5159 width = ((count - 1) * 6 + 4) * 8;
5167 width = (size + 6) * 8;
5175 int count = size + 1;
5176 width = ((count - 1) * 4 + 2) * 8;
5191 int size_x = (size & 0x0F) + 1;
5192 int size_y = ((size >> 4) & 0x0F) + 1;
5193 width = size_x * 32;
5194 height = size_y * 32;
5208 int count = size + 1;
5210 height = ((count - 1) * 5 + 4) * 8;
5220 height = (size + 6) * 8;
5227 int count = size + 1;
5229 height = ((count - 1) * 4 + 2) * 8;
5236 int count = size + 1;
5238 height = count * 6 * 8;
5245 int count = size + 1;
5247 height = ((count - 1) * 3 + 3) * 8;
5255 int count = size + 1;
5257 height = count * 2 * 8;
5264 width = (size + 8) * 8;
5273 int count = size + 1;
5274 width = count * 2 * 8;
5286 int count = (size & 0x0F) + 2;
5295 int count = (size & 0x0F) + 2;
5424 int count = (size + 1) * 2;
5425 width = (2 + count) * 8;
5434 int count = (size + 1) * 2;
5435 width = (2 + count) * 8;
5468 int size_h = (
object.size_ & 0x0F);
5469 int size_v = (
object.size_ >> 4) & 0x0F;
5470 width = (size_h + 1) * 8;
5471 height = (size_v + 1) * 8;
5476 return {width, height};
5480 [[maybe_unused]] std::span<const gfx::TileInfo> tiles,
5486 int subtype = obj.
size_ & 0x1F;
5487 auto result = manager.GetObjectInternal(obj.
id_, subtype);
5489 LOG_DEBUG(
"ObjectDrawer",
"Custom object 0x%03X subtype %d not found: %s",
5490 obj.
id_, subtype, result.status().message().data());
5494 auto custom_obj = result.value();
5495 if (!custom_obj || custom_obj->IsEmpty())
return;
5497 int tile_x = obj.
x_;
5498 int tile_y = obj.
y_;
5500 for (
const auto& entry : custom_obj->tiles) {
5505 WriteTile8(bg, tile_x + entry.rel_x, tile_y + entry.rel_y, tile_info);
5515 if (item_id == 0)
return;
5517 auto& bitmap = bg.
bitmap();
5518 if (!bitmap.is_active() || bitmap.width() == 0)
return;
5522 int pixel_x = (x * 8) + 2;
5523 int pixel_y = (y * 8) + 2;
5598 int bitmap_width = bitmap.width();
5599 int bitmap_height = bitmap.height();
5601 for (
int py = 0; py < 4; py++) {
5602 for (
int px = 0; px < 4; px++) {
5603 int dest_x = pixel_x + px;
5604 int dest_y = pixel_y + py;
5607 if (dest_x >= 0 && dest_x < bitmap_width &&
5608 dest_y >= 0 && dest_y < bitmap_height) {
5609 int offset = (dest_y * bitmap_width) + dest_x;
5610 bitmap.WriteToPixel(offset, color_idx);
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
std::vector< uint8_t > & mutable_priority_data()
Represents a bitmap image optimized for SNES ROM hacking.
void WriteToPixel(int position, uint8_t value)
Write a value to a pixel at the given position.
void set_modified(bool modified)
std::vector< uint8_t > & mutable_data()
SNES 16-bit tile metadata container.
static CustomObjectManager & Get()
static DrawRoutineRegistry & Get()
Interface for accessing dungeon game state.
Draws dungeon objects to background buffers using game patterns.
void DrawDiagonalAcute_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
int GetDrawRoutineId(int16_t object_id) const
Get draw routine ID for an object.
void WriteTile8(gfx::BackgroundBuffer &bg, int tile_x, int tile_y, const gfx::TileInfo &tile_info)
void DrawDiagonalGrave_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawBed4x5(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawClosedChestPlatform(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawRightwards2x4_1to15or26(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwards2x4_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawTileToBitmap(gfx::Bitmap &bitmap, const gfx::TileInfo &tile_info, int pixel_x, int pixel_y, const uint8_t *tiledata)
Draw a single tile directly to bitmap.
void InitializeDrawRoutines()
Initialize draw routine registry Must be called before drawing objects.
void DrawRightwardsPillar2x4spaced4_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwardsBottomCorners1x2_1to16_plus13(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwards4x4_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawUtility6x3(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwardsEdge1x1_1to16plus7(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
std::vector< DrawRoutine > draw_routines_
void DrawRightwardsDecor4x2spaced8_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDownwardsHammerPegs2x2_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDownwardsPillar2x4spaced2_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawHorizontalTurtleRockPipe(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDownwards2x2_1to15or32(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDiagonalCeilingBottomRight(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwardsBlock2x2spaced2_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawSingle2x2(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
std::pair< int, int > CalculateObjectDimensions(const RoomObject &object)
Calculate the dimensions (width, height) of an object in pixels.
void DrawDoorSwitcherer(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwards2x2_1to15or32(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
const uint8_t * room_gfx_buffer_
void DrawUtility3x5(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawSingle4x3(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRupeeFloor(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDownwardsEdge1x1_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDownwardsBar2x3_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
static bool RoutineDrawsToBothBGs(int routine_id)
void DrawDownwardsDecor2x4spaced8_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawNothing(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
absl::Status DrawObjectList(const std::vector< RoomObject > &objects, gfx::BackgroundBuffer &bg1, gfx::BackgroundBuffer &bg2, const gfx::PaletteGroup &palette_group, const DungeonState *state=nullptr, gfx::BackgroundBuffer *layout_bg1=nullptr)
Draw all objects in a room.
void DrawDownwardsDecor4x2spaced4_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwardsLine1x1_1to16plus1(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDoor(const DoorDef &door, int door_index, gfx::BackgroundBuffer &bg1, gfx::BackgroundBuffer &bg2, const DungeonState *state=nullptr)
Draw a door to background buffers.
void DrawDiagonalCeilingTopLeft(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwardsTopCorners1x2_1to16_plus13(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDownwardsHasEdge1x1_1to16_plus3(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDiagonalAcute_1to16_BothBG(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwards2x2_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawPotItem(uint8_t item_id, int x, int y, gfx::BackgroundBuffer &bg)
Draw a pot item visualization.
void DrawLargeCanvasObject(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, int width, int height)
void Draw4x4Corner_BothBG(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawBigLightBeam(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDownwardsCannonHole3x6_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDownwards2x2_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDownwardsLine1x1_1to16plus1(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawVerticalTurtleRockPipe(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwards4x2_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawCorner4x4(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwardsHasEdge1x1_1to16_plus3(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwardsHammerPegs2x2_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwards2x4_1to16_BothBG(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawCustomObject(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwardsStatue2x3spaced2_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDiagonalCeilingTopRight(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawWaterFace(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwardsDecor4x3spaced4_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwardsShelf4x4_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDiagonalGrave_1to16_BothBG(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawMovingWallEast(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawDownwardsPots2x2_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
std::unordered_map< int16_t, int > object_to_routine_map_
void DrawDownwardsFloor4x4_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDownwardsDecor3x4spaced2_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwardsPots2x2_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawActual4x4(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawOpenChestPlatform(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawRightwards1x1Solid_1to16_plus3(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void MarkBG1Transparent(gfx::BackgroundBuffer &bg1, int tile_x, int tile_y, int pixel_width, int pixel_height)
Mark BG1 pixels as transparent where BG2 overlay objects are drawn.
void DrawChest(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDownwardsDecor4x4spaced2_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void CustomDraw(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawSolidWallDecor3x4(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDiagonalCeilingBottomLeft(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwardsCannonHole4x3_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawWeirdCornerBottom_BothBG(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
bool routines_initialized_
void DrawRightwards3x6(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwardsHasEdge1x1_1to16_plus2(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDownwards4x2_1to15or26(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
ObjectDrawer(Rom *rom, int room_id, const uint8_t *room_gfx_buffer=nullptr)
void DrawRightwardsDecor4x4spaced2_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawSingle4x4(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawLightBeam(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
absl::Status DrawObject(const RoomObject &object, gfx::BackgroundBuffer &bg1, gfx::BackgroundBuffer &bg2, const gfx::PaletteGroup &palette_group, const DungeonState *state=nullptr, gfx::BackgroundBuffer *layout_bg1=nullptr)
Draw a room object to background buffers.
void DrawWeirdCornerTop_BothBG(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDownwards4x2_1to16_BothBG(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDownwardsDecor3x4spaced4_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDownwardsRightCorners2x1_1to16_plus12(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
static constexpr int kMaxTilesY
void DrawRightwardsDoubled2x2spaced2_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawBossShell4x4(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwards1x2_1to16_plus2(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawGanonTriforceFloorDecor(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwardsBar4x3_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
bool IsValidTilePosition(int tile_x, int tile_y) const
void DrawRightwardsDecor2x2spaced12_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDownwardsBlock2x2spaced2_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDoorIndicator(gfx::Bitmap &bitmap, int tile_x, int tile_y, int width, int height, DoorType type, DoorDirection direction)
void DrawDownwardsHasEdge1x1_1to16_plus23(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDownwards1x1Solid_1to16_plus3(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawSomariaLine(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawArcheryGameTargetDoor(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawRightwardsBigRail1x3_1to16plus5(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawMovingWallWest(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawDownwardsLeftCorners2x1_1to16_plus12(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDownwardsDecor2x2spaced12_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
void DrawDownwardsBigRail3x1_1to16plus5(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles, const DungeonState *state=nullptr)
const std::vector< gfx::TileInfo > & tiles() const
#define LOG_DEBUG(category, format,...)
TileInfo WordToTileInfo(uint16_t word)
constexpr int kDiagonalGrave_1to16_BothBG
constexpr int kCorner4x4_BothBG
constexpr int kRightwards2x4_1to16_BothBG
constexpr int kDownwards4x2_1to15or26
constexpr int kRightwards2x2_1to15or32
constexpr int kWeirdCornerBottom_BothBG
constexpr int kRightwards2x4_1to15or26
constexpr int kDownwards4x2_1to16_BothBG
constexpr int kCustomObject
constexpr int kWeirdCornerTop_BothBG
constexpr int kDiagonalAcute_1to16_BothBG
constexpr int kDownwardsHasEdge1x1_1to16_plus23
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 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 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 Draw4x4FloorTwoIn4x4SuperSquare(const DrawContext &ctx)
Draw two 4x4 floor pattern variant.
void DrawSpike2x2In4x4SuperSquare(const DrawContext &ctx)
Draw 2x2 spike pattern in super square units.
void DrawSpiralStairs(const DrawContext &ctx, bool going_up, bool is_upper)
Draw spiral stairs (Type 2 objects 0x138-0x13B)
void DrawBombableFloor(const DrawContext &ctx)
Draw bombable floor (Type 3 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 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 DrawStraightInterRoomStairs(const DrawContext &ctx)
Draw straight inter-room stairs (Type 3 objects 0x21E-0x229)
void DrawInterRoomFatStairsDownB(const DrawContext &ctx)
Draw inter-room fat stairs going down B (Type 2 object 0x12F)
void DrawWaterOverlay8x8_1to16(const DrawContext &ctx)
Draw water overlay 8x8 pattern.
void Draw4x4FloorOneIn4x4SuperSquare(const DrawContext &ctx)
Draw single 4x4 floor pattern variant.
void DrawBigKeyLock(const DrawContext &ctx)
Draw big key lock (Type 3 object 0x218)
void DrawPrisonCell(const DrawContext &ctx)
Draw prison cell with bars (Type 3 objects 0x20D, 0x217)
DoorType
Door types from ALTTP.
@ TopShutterLower
Top-sided shutter door (lower layer)
@ FancyDungeonExitLower
Fancy dungeon exit (lower layer)
@ FancyDungeonExit
Fancy dungeon exit.
@ SmallKeyDoor
Small key door.
@ SmallKeyStairsDown
Small key stairs (downwards)
@ BombableCaveExit
Bombable cave exit.
@ SmallKeyStairsUp
Small key stairs (upwards)
@ DungeonSwapMarker
Dungeon swap marker.
@ NormalDoor
Normal door (upper layer)
@ BombableDoor
Bombable door.
@ LayerSwapMarker
Layer swap marker.
@ BottomShutterLower
Bottom-sided shutter door (lower layer)
@ ExplodingWall
Exploding wall.
@ TopSidedShutter
Top-sided shutter door.
@ LitCaveExitLower
Lit cave exit (lower layer)
@ DoubleSidedShutterLower
Double-sided shutter (lower layer)
@ UnopenableBigKeyDoor
Unopenable, double-sided big key door.
@ NormalDoorLower
Normal door (lower layer)
@ BottomSidedShutter
Bottom-sided shutter door.
@ SmallKeyStairsDownLower
Small key stairs (lower layer; downwards)
@ CurtainDoor
Curtain door.
@ WaterfallDoor
Waterfall door.
@ BigKeyDoor
Big key door.
@ EyeWatchDoor
Eye watch door.
@ SmallKeyStairsUpLower
Small key stairs (lower layer; upwards)
@ DoubleSidedShutter
Double sided shutter door.
constexpr int kDoorGfxDown
constexpr std::string_view GetDoorDirectionName(DoorDirection dir)
Get human-readable name for door direction.
constexpr int kDoorGfxLeft
constexpr std::string_view GetDoorTypeName(DoorType type)
Get human-readable name for door type.
DoorDirection
Door direction on room walls.
@ South
Bottom wall (horizontal door, 4x3 tiles)
@ North
Top wall (horizontal door, 4x3 tiles)
@ East
Right wall (vertical door, 3x4 tiles)
@ West
Left wall (vertical door, 3x4 tiles)
constexpr int kDoorGfxRight
bool kEnableCustomObjects
Represents a group of palettes.
int width_tiles
Width in 8x8 tiles.
Context passed to draw routines containing all necessary state.
std::pair< int, int > GetTileCoords() const
DoorDimensions GetDimensions() const