6#include "absl/strings/str_format.h"
20static constexpr uint8_t kSubtype1TileLengths[0xF8] = {
21 4, 8, 8, 8, 8, 8, 8, 4, 4, 5, 5, 5, 5, 5, 5, 5,
22 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
23 5, 9, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6,
24 6, 1, 1, 16, 1, 1, 16, 16, 6, 8, 12, 12, 4, 8, 4, 3,
25 3, 3, 3, 3, 3, 3, 3, 0, 0, 8, 8, 4, 9, 16, 16, 16,
26 1, 18, 18, 4, 1, 8, 8, 1, 1, 1, 1, 18, 18, 15, 4, 3,
27 4, 8, 8, 8, 8, 8, 8, 4, 4, 3, 1, 1, 6, 6, 1, 1,
28 16, 1, 1, 16, 16, 8, 16, 16, 4, 1, 1, 4, 1, 4, 1, 8,
29 8, 12, 12, 12, 12, 18, 18, 8, 12, 4, 3, 3, 3, 1, 1, 6,
30 8, 8, 4, 4, 16, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1,
31 1, 1, 1, 1, 24, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
32 1, 1, 16, 3, 3, 8, 8, 8, 4, 4, 16, 4, 4, 4, 1, 1,
33 1, 68, 1, 1, 8, 8, 8, 8, 8, 8, 8, 1, 1, 28, 28, 1,
34 1, 8, 8, 0, 0, 0, 0, 1, 8, 8, 8, 8, 21, 16, 4, 8,
35 8, 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1,
36 1, 1, 1, 1, 1, 1, 1, 1
41static inline int GetSubtype1TileCount(
int object_id) {
42 int index = object_id & 0xFF;
44 int count = kSubtype1TileLengths[index];
45 return (count > 0) ? count : 8;
55 if (
rom_ ==
nullptr) {
56 return absl::InvalidArgumentError(
"ROM is null");
61 return absl::InvalidArgumentError(
62 absl::StrFormat(
"Invalid object ID: %d", object_id));
75 return absl::InvalidArgumentError(
76 absl::StrFormat(
"Invalid object subtype for ID: %#04x", object_id));
82 if (
rom_ ==
nullptr) {
83 return absl::InvalidArgumentError(
"ROM is null");
87 if (!subtype_info.ok()) {
88 return subtype_info.status();
92 routine_info.
routine_ptr = subtype_info->routine_ptr;
93 routine_info.
tile_ptr = subtype_info->subtype_ptr;
94 routine_info.
tile_count = subtype_info->max_tile_count;
108 int index = object_id & 0xFF;
112 GetSubtype1TileCount(object_id);
118 int index = (object_id - 0x100) & 0x3F;
128 int index = (object_id - 0xF80) & 0x7F;
135 return absl::InvalidArgumentError(
136 absl::StrFormat(
"Invalid object subtype for ID: %#04x", object_id));
143 int16_t object_id, uint8_t size_byte) {
147 int size_x = size_byte & 0x03;
148 int size_y = (size_byte >> 2) & 0x03;
155 if (object_id >= 0x80 && object_id <= 0xFF) {
172 int index = object_id & 0xFF;
175 if (tile_ptr + 1 >= (
int)
rom_->
size()) {
176 return absl::OutOfRangeError(
177 absl::StrFormat(
"Tile pointer out of range: %#06x", tile_ptr));
181 uint8_t low =
rom_->
data()[tile_ptr];
182 uint8_t high =
rom_->
data()[tile_ptr + 1];
183 int16_t offset = (int16_t)((high << 8) | low);
187 bool is_debug_object = (object_id == 0x61 || object_id == 0x62 ||
188 object_id == 0xC0 || object_id == 0xC2);
189 static int debug_count = 0;
190 if (debug_count < 10 || is_debug_object) {
192 "ParseSubtype1: obj=0x%02X%s tile_ptr=0x%04X (SNES $01:%04X)",
193 object_id, is_debug_object ?
" (DEBUG)" :
"", tile_ptr, tile_ptr);
195 " ROM[0x%04X..0x%04X]=0x%02X 0x%02X offset=%d (0x%04X)",
196 tile_ptr, tile_ptr + 1, low, high, offset, (uint16_t)offset);
198 " tile_data_ptr=0x%04X+0x%04X=0x%04X (SNES $00:%04X)",
200 tile_data_ptr + 0x8000);
203 if (tile_data_ptr >= 0 && tile_data_ptr + 8 < (
int)
rom_->
size()) {
206 uint16_t tw1 =
rom_->
data()[tile_data_ptr + 2] |
207 (
rom_->
data()[tile_data_ptr + 3] << 8);
208 LOG_DEBUG(
"ObjectParser",
" First 2 tiles: $%04X(id=%d) $%04X(id=%d)",
209 tw0, tw0 & 0x3FF, tw1, tw1 & 0x3FF);
211 LOG_DEBUG(
"ObjectParser",
" Tile data at 0x%04X: <OUT OF BOUNDS>",
214 if (!is_debug_object)
219 int tile_count = GetSubtype1TileCount(object_id);
226 int index = (object_id - 0x100) & 0x3F;
229 if (tile_ptr + 1 >= (
int)
rom_->
size()) {
230 return absl::OutOfRangeError(
231 absl::StrFormat(
"Tile pointer out of range: %#06x", tile_ptr));
235 uint8_t low =
rom_->
data()[tile_ptr];
236 uint8_t high =
rom_->
data()[tile_ptr + 1];
243 bool is_corner = (object_id >= 0x100 && object_id <= 0x103);
246 "ParseSubtype2: CORNER obj=0x%03X index=%d tile_ptr=0x%04X",
247 object_id, index, tile_ptr);
249 " ROM[0x%04X..0x%04X]=0x%02X 0x%02X offset=0x%04X", tile_ptr,
250 tile_ptr + 1, low, high, (high << 8) | low);
252 "ObjectParser",
" tile_data_ptr=0x%04X+0x%04X=0x%04X (tile_count=%d)",
256 if (tile_data_ptr >= 0 && tile_data_ptr + 4 < (
int)
rom_->
size()) {
259 uint16_t tw1 =
rom_->
data()[tile_data_ptr + 2] |
260 (
rom_->
data()[tile_data_ptr + 3] << 8);
261 LOG_DEBUG(
"ObjectParser",
" First 2 tiles: $%04X(id=%d) $%04X(id=%d)",
262 tw0, tw0 & 0x3FF, tw1, tw1 & 0x3FF);
273 int index = (object_id - 0xF80) & 0x7F;
276 if (tile_ptr + 1 >= (
int)
rom_->
size()) {
277 return absl::OutOfRangeError(
278 absl::StrFormat(
"Tile pointer out of range: %#06x", tile_ptr));
282 uint8_t low =
rom_->
data()[tile_ptr];
283 uint8_t high =
rom_->
data()[tile_ptr + 1];
292 int address,
int tile_count) {
296 if (address < 0 || address + (tile_count * 2) >= (
int)
rom_->
size()) {
297 return absl::OutOfRangeError(
298 absl::StrFormat(
"Tile data address out of range: %#06x", address));
301 std::vector<gfx::TileInfo> tiles;
302 tiles.reserve(tile_count);
305 static int debug_read_count = 0;
306 bool should_log = (debug_read_count < 3);
308 for (
int i = 0; i < tile_count; i++) {
309 int tile_offset = address + (i * 2);
316 tiles.push_back(tile_info);
319 if (should_log && i < 4) {
321 "ReadTile[%d]: addr=0x%06X word=0x%04X id=0x%03X pal=%d "
322 "mirror=(h:%d,v:%d)",
323 i, tile_offset, tile_word, tile_info.id_, tile_info.palette_,
324 tile_info.horizontal_mirror_, tile_info.vertical_mirror_);
330 "ReadTileData: addr=0x%06X count=%d loaded %zu tiles", address,
331 tile_count, tiles.size());
341 if (object_id >= 0x100 && object_id <= 0x10F) {
346 if (object_id >= 0x110 && object_id <= 0x117) {
356 if (object_id == 0xFB1 || object_id == 0xFB2) {
360 if (object_id == 0xF94 || object_id == 0xFCE ||
361 (object_id >= 0xFE7 && object_id <= 0xFE8) ||
362 (object_id >= 0xFEC && object_id <= 0xFED)) {
367 if (object_id == 0xFC8 || object_id == 0xFE6 || object_id == 0xFEB ||
368 object_id == 0xFFA) {
377 if (object_id >= 0xF80) {
379 }
else if (object_id >= 0x100) {
392 if (object_id == 0x00) {
397 }
else if (object_id >= 0x01 && object_id <= 0x02) {
402 }
else if (object_id >= 0x03 && object_id <= 0x04) {
407 }
else if (object_id >= 0x05 && object_id <= 0x06) {
409 info.
routine_name =
"Rightwards2x4spaced4_1to16_BothBG";
413 }
else if (object_id >= 0x07 && object_id <= 0x08) {
418 }
else if (object_id == 0x09) {
423 }
else if (object_id >= 0x0A && object_id <= 0x0B) {
428 }
else if (object_id >= 0x0C && object_id <= 0x0D) {
434 }
else if (object_id >= 0x0E && object_id <= 0x0F) {
440 }
else if (object_id >= 0x10 && object_id <= 0x11) {
446 }
else if (object_id >= 0x12 && object_id <= 0x13) {
452 }
else if (object_id >= 0x14 && object_id <= 0x15) {
458 }
else if (object_id >= 0x16 && object_id <= 0x17) {
464 }
else if (object_id >= 0x18 && object_id <= 0x19) {
470 }
else if (object_id >= 0x1A && object_id <= 0x1B) {
476 }
else if (object_id >= 0x1C && object_id <= 0x1D) {
482 }
else if (object_id >= 0x1E && object_id <= 0x1F) {
488 }
else if (object_id == 0x20) {
494 }
else if (object_id == 0x21) {
499 }
else if (object_id == 0x22) {
504 }
else if (object_id >= 0x23 && object_id <= 0x24) {
509 }
else if (object_id >= 0x25 && object_id <= 0x26) {
514 }
else if (object_id == 0x27) {
516 info.
routine_name =
"RightwardsTopCorners1x2_1to16_plus13";
519 }
else if (object_id == 0x28) {
522 info.
routine_name =
"RightwardsBottomCorners1x2_1to16_plus13";
525 }
else if (object_id >= 0x29 && object_id <= 0x2E) {
530 }
else if (object_id == 0x2F) {
532 info.
routine_name =
"RightwardsTopCorners1x2_1to16_plus13";
535 }
else if (object_id == 0x30) {
538 info.
routine_name =
"RightwardsBottomCorners1x2_1to16_plus13";
541 }
else if (object_id >= 0x31 && object_id <= 0x32) {
545 }
else if (object_id == 0x33) {
550 }
else if (object_id == 0x34) {
555 }
else if (object_id == 0x35) {
559 }
else if (object_id >= 0x36 && object_id <= 0x37) {
564 }
else if (object_id == 0x38) {
569 }
else if (object_id == 0x39 || object_id == 0x3D) {
574 }
else if (object_id >= 0x3A && object_id <= 0x3B) {
579 }
else if (object_id == 0x3C) {
581 info.
routine_name =
"RightwardsDoubled2x2spaced2_1to16";
584 }
else if (object_id == 0x3E) {
589 }
else if (object_id >= 0x3F && object_id <= 0x40) {
595 }
else if (object_id >= 0x40 && object_id <= 0x4F) {
600 }
else if (object_id >= 0x60 && object_id <= 0x6F) {
602 if (object_id == 0x60) {
607 }
else if (object_id >= 0x61 && object_id <= 0x62) {
612 }
else if (object_id >= 0x63 && object_id <= 0x64) {
618 }
else if (object_id >= 0x65 && object_id <= 0x66) {
623 }
else if (object_id >= 0x67 && object_id <= 0x68) {
628 }
else if (object_id == 0x69) {
633 }
else if (object_id >= 0x6A && object_id <= 0x6B) {
638 }
else if (object_id == 0x6C) {
641 info.
routine_name =
"DownwardsLeftCorners2x1_1to16_plus12";
644 }
else if (object_id == 0x6D) {
647 info.
routine_name =
"DownwardsRightCorners2x1_1to16_plus12";
655 }
else if (object_id >= 0x100 && object_id <= 0x10F) {
absl::StatusOr< ObjectSubtypeInfo > GetObjectSubtype(int16_t object_id)
Get object subtype information.
absl::StatusOr< ObjectRoutineInfo > ParseObjectRoutine(int16_t object_id)
Parse object routine data.
absl::StatusOr< ObjectSizeInfo > ParseObjectSize(int16_t object_id, uint8_t size_byte)
Parse object size and orientation.
int GetSubtype3TileCount(int16_t object_id) const
Get tile count for subtype 3 objects.
absl::StatusOr< std::vector< gfx::TileInfo > > ParseSubtype2(int16_t object_id)
Parse subtype 2 objects (0x100-0x1FF)
absl::StatusOr< std::vector< gfx::TileInfo > > ParseObject(int16_t object_id)
Parse object data directly from ROM.
int GetSubtype2TileCount(int16_t object_id) const
Get tile count for subtype 2 objects.
absl::StatusOr< std::vector< gfx::TileInfo > > ParseSubtype1(int16_t object_id)
Parse subtype 1 objects (0x00-0xFF)
absl::StatusOr< std::vector< gfx::TileInfo > > ParseSubtype3(int16_t object_id)
Parse subtype 3 objects (0x200+)
absl::StatusOr< std::vector< gfx::TileInfo > > ReadTileData(int address, int tile_count)
Read tile data from ROM.
ObjectDrawInfo GetObjectDrawInfo(int16_t object_id) const
Get draw routine information for an object.
int DetermineSubtype(int16_t object_id) const
Determine object subtype from ID.
#define LOG_DEBUG(category, format,...)
TileInfo WordToTileInfo(uint16_t word)
constexpr int kRoomObjectSubtype3
constexpr int kRoomObjectSubtype1
constexpr int kRoomObjectSubtype2
constexpr int kRoomObjectTileAddress
Draw routine information for object rendering.
Object routine information.
bool is_orientation_dependent
Object size and orientation information.
Object subtype information.