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;
117 int index = (object_id - 0x100) & 0x3F;
127 int index = (object_id - 0xF80) & 0x7F;
134 return absl::InvalidArgumentError(
135 absl::StrFormat(
"Invalid object subtype for ID: %#04x", object_id));
142 int16_t object_id, uint8_t size_byte) {
146 int size_x = size_byte & 0x03;
147 int size_y = (size_byte >> 2) & 0x03;
154 if (object_id >= 0x80 && object_id <= 0xFF) {
171 int index = object_id & 0xFF;
174 if (tile_ptr + 1 >= (
int)
rom_->
size()) {
175 return absl::OutOfRangeError(
176 absl::StrFormat(
"Tile pointer out of range: %#06x", tile_ptr));
180 uint8_t low =
rom_->
data()[tile_ptr];
181 uint8_t high =
rom_->
data()[tile_ptr + 1];
182 int16_t offset = (int16_t)((high << 8) | low);
186 bool is_wall_object = (object_id == 0x61 || object_id == 0x62);
187 static int debug_count = 0;
188 if (debug_count < 10 || is_wall_object) {
189 printf(
"[ParseSubtype1] obj=0x%02X%s: tile_ptr=0x%04X (SNES $01:%04X)\n",
190 object_id, is_wall_object ?
" (WALL)" :
"", tile_ptr, tile_ptr);
191 printf(
" ROM[0x%04X..0x%04X] = 0x%02X 0x%02X -> offset=%d (0x%04X)\n",
192 tile_ptr, tile_ptr+1, low, high, offset, (uint16_t)offset);
193 printf(
" tile_data_ptr = 0x%04X + 0x%04X = 0x%04X (SNES $00:%04X)\n",
195 tile_data_ptr + 0x8000);
198 int num_tiles = is_wall_object ? 8 : 4;
200 if (tile_data_ptr >= 0 && tile_data_ptr + (num_tiles * 2) < (
int)
rom_->
size()) {
201 printf(
" Tile data at 0x%04X: ", tile_data_ptr);
202 for (
int i = 0; i < num_tiles; i++) {
203 uint16_t tw =
rom_->
data()[tile_data_ptr + i*2] |
204 (
rom_->
data()[tile_data_ptr + i*2 + 1] << 8);
205 uint16_t tid = tw & 0x3FF;
206 uint8_t pal = (tw >> 10) & 0x07;
207 bool hflip = (tw >> 14) & 0x01;
208 bool vflip = (tw >> 15) & 0x01;
209 printf(
"$%04X(id=%d,p=%d,h:%d,v:%d) ", tw, tid, pal, hflip, vflip);
210 if (i == 3 && is_wall_object) printf(
"\n ");
214 printf(
" Tile data at 0x%04X: <OUT OF BOUNDS>\n", tile_data_ptr);
216 if (!is_wall_object) debug_count++;
220 int tile_count = GetSubtype1TileCount(object_id);
227 int index = (object_id - 0x100) & 0x3F;
230 if (tile_ptr + 1 >= (
int)
rom_->
size()) {
231 return absl::OutOfRangeError(
232 absl::StrFormat(
"Tile pointer out of range: %#06x", tile_ptr));
236 uint8_t low =
rom_->
data()[tile_ptr];
237 uint8_t high =
rom_->
data()[tile_ptr + 1];
244 bool is_corner = (object_id >= 0x100 && object_id <= 0x103);
246 printf(
"[ParseSubtype2] CORNER obj=0x%03X: index=%d tile_ptr=0x%04X\n",
247 object_id, index, tile_ptr);
248 printf(
" ROM[0x%04X..0x%04X] = 0x%02X 0x%02X -> offset=0x%04X\n",
249 tile_ptr, tile_ptr+1, low, high, (high << 8) | low);
250 printf(
" tile_data_ptr = 0x%04X + 0x%04X = 0x%04X (tile_count=%d)\n",
254 if (tile_data_ptr >= 0 && tile_data_ptr + 8 < (
int)
rom_->
size()) {
255 printf(
" First 4 tiles: ");
256 for (
int i = 0; i < 4; i++) {
257 uint16_t tw =
rom_->
data()[tile_data_ptr + i*2] |
258 (
rom_->
data()[tile_data_ptr + i*2 + 1] << 8);
259 uint16_t tid = tw & 0x3FF;
260 printf(
"$%04X(id=%d) ", tw, tid);
274 int index = (object_id - 0xF80) & 0x7F;
277 if (tile_ptr + 1 >= (
int)
rom_->
size()) {
278 return absl::OutOfRangeError(
279 absl::StrFormat(
"Tile pointer out of range: %#06x", tile_ptr));
283 uint8_t low =
rom_->
data()[tile_ptr];
284 uint8_t high =
rom_->
data()[tile_ptr + 1];
293 int address,
int tile_count) {
297 if (address < 0 || address + (tile_count * 2) >= (
int)
rom_->
size()) {
298 return absl::OutOfRangeError(
299 absl::StrFormat(
"Tile data address out of range: %#06x", address));
302 std::vector<gfx::TileInfo> tiles;
303 tiles.reserve(tile_count);
306 static int debug_read_count = 0;
307 bool should_log = (debug_read_count < 3);
309 for (
int i = 0; i < tile_count; i++) {
310 int tile_offset = address + (i * 2);
317 tiles.push_back(tile_info);
320 if (should_log && i < 4) {
322 "[ObjectParser] ReadTile[%d]: addr=0x%06X word=0x%04X → id=0x%03X "
323 "pal=%d mirror=(h:%d,v:%d)\n",
324 i, tile_offset, tile_word, tile_info.id_, tile_info.palette_,
325 tile_info.horizontal_mirror_, tile_info.vertical_mirror_);
331 "[ObjectParser] ReadTileData: addr=0x%06X count=%d → loaded %zu "
333 address, tile_count, tiles.size());
343 if (object_id >= 0x100 && object_id <= 0x10F) {
348 if (object_id >= 0x110 && object_id <= 0x117) {
358 if (object_id == 0xFB1 || object_id == 0xFB2) {
362 if (object_id == 0xF94 || object_id == 0xFCE ||
363 (object_id >= 0xFE7 && object_id <= 0xFE8) ||
364 (object_id >= 0xFEC && object_id <= 0xFED)) {
369 if (object_id == 0xFC8 || object_id == 0xFE6 ||
370 object_id == 0xFEB || object_id == 0xFFA) {
379 if (object_id >= 0xF80) {
381 }
else if (object_id >= 0x100) {
394 if (object_id == 0x00) {
399 }
else if (object_id >= 0x01 && object_id <= 0x02) {
404 }
else if (object_id >= 0x03 && object_id <= 0x04) {
409 }
else if (object_id >= 0x05 && object_id <= 0x06) {
411 info.
routine_name =
"Rightwards2x4spaced4_1to16_BothBG";
415 }
else if (object_id >= 0x07 && object_id <= 0x08) {
420 }
else if (object_id == 0x09) {
425 }
else if (object_id >= 0x0A && object_id <= 0x0B) {
430 }
else if (object_id >= 0x0C && object_id <= 0x0D) {
436 }
else if (object_id >= 0x0E && object_id <= 0x0F) {
442 }
else if (object_id >= 0x10 && object_id <= 0x11) {
448 }
else if (object_id >= 0x12 && object_id <= 0x13) {
454 }
else if (object_id >= 0x14 && object_id <= 0x15) {
460 }
else if (object_id >= 0x16 && object_id <= 0x17) {
466 }
else if (object_id >= 0x18 && object_id <= 0x19) {
472 }
else if (object_id >= 0x1A && object_id <= 0x1B) {
478 }
else if (object_id >= 0x1C && object_id <= 0x1D) {
484 }
else if (object_id >= 0x1E && object_id <= 0x1F) {
490 }
else if (object_id == 0x20) {
496 }
else if (object_id == 0x21) {
501 }
else if (object_id == 0x22) {
506 }
else if (object_id >= 0x23 && object_id <= 0x24) {
511 }
else if (object_id >= 0x25 && object_id <= 0x26) {
516 }
else if (object_id == 0x27) {
518 info.
routine_name =
"RightwardsTopCorners1x2_1to16_plus13";
521 }
else if (object_id == 0x28) {
523 info.
routine_name =
"RightwardsBottomCorners1x2_1to16_plus13";
526 }
else if (object_id >= 0x29 && object_id <= 0x2E) {
531 }
else if (object_id == 0x2F) {
533 info.
routine_name =
"RightwardsTopCorners1x2_1to16_plus13";
536 }
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) {
594 }
else if (object_id >= 0x40 && object_id <= 0x4F) {
599 }
else if (object_id >= 0x60 && object_id <= 0x6F) {
601 if (object_id == 0x60) {
606 }
else if (object_id >= 0x61 && object_id <= 0x62) {
611 }
else if (object_id >= 0x63 && object_id <= 0x64) {
617 }
else if (object_id >= 0x65 && object_id <= 0x66) {
622 }
else if (object_id >= 0x67 && object_id <= 0x68) {
627 }
else if (object_id == 0x69) {
632 }
else if (object_id >= 0x6A && object_id <= 0x6B) {
637 }
else if (object_id == 0x6C) {
639 info.
routine_name =
"DownwardsLeftCorners2x1_1to16_plus12";
642 }
else if (object_id == 0x6D) {
644 info.
routine_name =
"DownwardsRightCorners2x1_1to16_plus12";
652 }
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.
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.