diff --git a/src/app/zelda3/screen/dungeon_map.cc b/src/app/zelda3/screen/dungeon_map.cc index f9e6da26..c95b03ba 100644 --- a/src/app/zelda3/screen/dungeon_map.cc +++ b/src/app/zelda3/screen/dungeon_map.cc @@ -7,13 +7,171 @@ #include "app/core/platform/renderer.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" +#include "app/gfx/tilemap.h" +#include "app/snes.h" +#include "util/hex.h" namespace yaze { namespace zelda3 { +absl::StatusOr> LoadDungeonMaps( + Rom &rom, DungeonMapLabels &dungeon_map_labels) { + std::vector dungeon_maps; + std::vector> current_floor_rooms_d; + std::vector> current_floor_gfx_d; + int total_floors_d; + uint8_t nbr_floor_d; + uint8_t nbr_basement_d; + + for (int d = 0; d < kNumDungeons; d++) { + current_floor_rooms_d.clear(); + current_floor_gfx_d.clear(); + ASSIGN_OR_RETURN(int ptr, + rom.ReadWord(zelda3::kDungeonMapRoomsPtr + (d * 2))); + ASSIGN_OR_RETURN(int ptr_gfx, + rom.ReadWord(zelda3::kDungeonMapGfxPtr + (d * 2))); + ptr |= 0x0A0000; // Add bank to the short ptr + ptr_gfx |= 0x0A0000; // Add bank to the short ptr + int pc_ptr = SnesToPc(ptr); // Contains data for the next 25 rooms + int pc_ptr_gfx = SnesToPc(ptr_gfx); // Contains data for the next 25 rooms + + ASSIGN_OR_RETURN(uint16_t boss_room_d, + rom.ReadWord(zelda3::kDungeonMapBossRooms + (d * 2))); + + ASSIGN_OR_RETURN(nbr_basement_d, + rom.ReadByte(zelda3::kDungeonMapFloors + (d * 2))); + nbr_basement_d &= 0x0F; + + ASSIGN_OR_RETURN(nbr_floor_d, + rom.ReadByte(zelda3::kDungeonMapFloors + (d * 2))); + nbr_floor_d &= 0xF0; + nbr_floor_d = nbr_floor_d >> 4; + + total_floors_d = nbr_basement_d + nbr_floor_d; + + // for each floor in the dungeon + for (int i = 0; i < total_floors_d; i++) { + dungeon_map_labels[d].emplace_back(); + + std::array rdata; + std::array gdata; + + // for each room on the floor + for (int j = 0; j < 25; j++) { + gdata[j] = 0xFF; + rdata[j] = rom.data()[pc_ptr + j + (i * 25)]; // Set the rooms + + if (rdata[j] == 0x0F) { + gdata[j] = 0xFF; + } else { + gdata[j] = rom.data()[pc_ptr_gfx++]; + } + + std::string label = util::HexByte(rdata[j]); + dungeon_map_labels[d][i][j] = label; + } + + current_floor_gfx_d.push_back(gdata); // Add new floor gfx data + current_floor_rooms_d.push_back(rdata); // Add new floor data + } + + dungeon_maps.emplace_back(boss_room_d, nbr_floor_d, nbr_basement_d, + current_floor_rooms_d, current_floor_gfx_d); + } + + return dungeon_maps; +} + +absl::Status SaveDungeonMaps(Rom &rom, std::vector &dungeon_maps) { + for (int d = 0; d < kNumDungeons; d++) { + int ptr = zelda3::kDungeonMapRoomsPtr + (d * 2); + int ptr_gfx = zelda3::kDungeonMapGfxPtr + (d * 2); + int pc_ptr = SnesToPc(ptr); + int pc_ptr_gfx = SnesToPc(ptr_gfx); + + const int nbr_floors = dungeon_maps[d].nbr_of_floor; + const int nbr_basements = dungeon_maps[d].nbr_of_basement; + for (int i = 0; i < nbr_floors + nbr_basements; i++) { + for (int j = 0; j < 25; j++) { + RETURN_IF_ERROR(rom.WriteByte(pc_ptr + j + (i * 25), + dungeon_maps[d].floor_rooms[i][j])); + RETURN_IF_ERROR(rom.WriteByte(pc_ptr_gfx + j + (i * 25), + dungeon_maps[d].floor_gfx[i][j])); + pc_ptr_gfx++; + } + } + } + + return absl::OkStatus(); +} + +absl::Status LoadDungeonMapTile16(gfx::Tilemap &tile16_blockset, Rom &rom, + const std::vector &gfx_data, + bool bin_mode) { + tile16_blockset.tile_size = {16, 16}; + tile16_blockset.map_size = {186, 186}; + tile16_blockset.atlas.Create(256, 192, 8, + std::vector(256 * 192, 0x00)); + + for (int i = 0; i < 186; i++) { + int addr = zelda3::kDungeonMapTile16; + if (rom.data()[zelda3::kDungeonMapExpCheck] != 0xB9) { + addr = zelda3::kDungeonMapTile16Expanded; + } + + ASSIGN_OR_RETURN(auto tl, rom.ReadWord(addr + (i * 8))); + gfx::TileInfo t1 = gfx::WordToTileInfo(tl); // Top left + + ASSIGN_OR_RETURN(auto tr, rom.ReadWord(addr + 2 + (i * 8))); + gfx::TileInfo t2 = gfx::WordToTileInfo(tr); // Top right + + ASSIGN_OR_RETURN(auto bl, rom.ReadWord(addr + 4 + (i * 8))); + gfx::TileInfo t3 = gfx::WordToTileInfo(bl); // Bottom left + + ASSIGN_OR_RETURN(auto br, rom.ReadWord(addr + 6 + (i * 8))); + gfx::TileInfo t4 = gfx::WordToTileInfo(br); // Bottom right + + int sheet_offset = 212; + if (bin_mode) { + sheet_offset = 0; + } + ComposeTile16(tile16_blockset, gfx_data, t1, t2, t3, t4, sheet_offset); + } + + tile16_blockset.atlas.SetPalette(*rom.mutable_dungeon_palette(3)); + core::Renderer::Get().RenderBitmap(&tile16_blockset.atlas); + return absl::OkStatus(); +} + +absl::Status SaveDungeonMapTile16(gfx::Tilemap &tile16_blockset, Rom &rom) { + for (int i = 0; i < 186; i++) { + int addr = zelda3::kDungeonMapTile16; + if (rom.data()[zelda3::kDungeonMapExpCheck] != 0xB9) { + addr = zelda3::kDungeonMapTile16Expanded; + } + + gfx::TileInfo t1 = tile16_blockset.tile_info[i][0]; + gfx::TileInfo t2 = tile16_blockset.tile_info[i][1]; + gfx::TileInfo t3 = tile16_blockset.tile_info[i][2]; + gfx::TileInfo t4 = tile16_blockset.tile_info[i][3]; + + auto tl = gfx::TileInfoToWord(t1); + RETURN_IF_ERROR(rom.WriteWord(addr + (i * 8), tl)); + + auto tr = gfx::TileInfoToWord(t2); + RETURN_IF_ERROR(rom.WriteWord(addr + 2 + (i * 8), tr)); + + auto bl = gfx::TileInfoToWord(t3); + RETURN_IF_ERROR(rom.WriteWord(addr + 4 + (i * 8), bl)); + + auto br = gfx::TileInfoToWord(t4); + RETURN_IF_ERROR(rom.WriteWord(addr + 6 + (i * 8), br)); + } + return absl::OkStatus(); +} + absl::Status LoadDungeonMapGfxFromBinary(Rom &rom, std::array &sheets, - gfx::Tilesheet &tile16_sheet, std::vector &gfx_bin_data) { std::string bin_file = core::FileDialogWrapper::ShowOpenFileDialog(); if (bin_file.empty()) { @@ -27,19 +185,18 @@ absl::Status LoadDungeonMapGfxFromBinary(Rom &rom, std::istreambuf_iterator()); auto converted_bin = gfx::SnesTo8bppSheet(bin_data, 4, 4); gfx_bin_data = converted_bin; - tile16_sheet.clear(); - if (LoadDungeonMapTile16(converted_bin, true).ok()) { - std::vector> gfx_sheets; - for (int i = 0; i < 4; i++) { - gfx_sheets.emplace_back(converted_bin.begin() + (i * 0x1000), - converted_bin.begin() + ((i + 1) * 0x1000)); - sheets[i] = gfx::Bitmap(128, 32, 8, gfx_sheets[i]); - sheets[i].SetPalette(*rom.mutable_dungeon_palette(3)); - core::Renderer::Get().RenderBitmap(&sheets[i]); - } - } else { - return absl::InternalError("Failed to load dungeon map tile16"); - } + // if (LoadDungeonMapTile16(converted_bin, true).ok()) { + // std::vector> gfx_sheets; + // for (int i = 0; i < 4; i++) { + // gfx_sheets.emplace_back(converted_bin.begin() + (i * 0x1000), + // converted_bin.begin() + ((i + 1) * 0x1000)); + // sheets[i] = gfx::Bitmap(128, 32, 8, gfx_sheets[i]); + // sheets[i].SetPalette(*rom.mutable_dungeon_palette(3)); + // core::Renderer::Get().RenderBitmap(&sheets[i]); + // } + // } else { + // return absl::InternalError("Failed to load dungeon map tile16"); + // } file.close(); } diff --git a/src/app/zelda3/screen/dungeon_map.h b/src/app/zelda3/screen/dungeon_map.h index 507b147e..0a07e484 100644 --- a/src/app/zelda3/screen/dungeon_map.h +++ b/src/app/zelda3/screen/dungeon_map.h @@ -5,7 +5,8 @@ #include #include "absl/status/status.h" -#include "app/gfx/tilesheet.h" +#include "app/gfx/bitmap.h" +#include "app/gfx/tilemap.h" #include "app/rom.h" namespace yaze { @@ -31,17 +32,20 @@ constexpr int kTriforceFaces = 0x04FFE4; // group of 5 constexpr int kCrystalVertices = 0x04FF98; +constexpr int kNumDungeons = 14; +constexpr int kNumRooms = 25; + struct DungeonMap { unsigned short boss_room = 0xFFFF; unsigned char nbr_of_floor = 0; unsigned char nbr_of_basement = 0; - std::vector> floor_rooms; - std::vector> floor_gfx; + std::vector> floor_rooms; + std::vector> floor_gfx; DungeonMap(unsigned short boss_room, unsigned char nbr_of_floor, unsigned char nbr_of_basement, - const std::vector> &floor_rooms, - const std::vector> &floor_gfx) + const std::vector> &floor_rooms, + const std::vector> &floor_gfx) : boss_room(boss_room), nbr_of_floor(nbr_of_floor), nbr_of_basement(nbr_of_basement), @@ -49,12 +53,22 @@ struct DungeonMap { floor_gfx(floor_gfx) {} }; -absl::Status LoadDungeonMapTile16(const std::vector &gfx_data, +using DungeonMapLabels = + std::array>, kNumDungeons>; + +absl::StatusOr> LoadDungeonMaps( + Rom &rom, DungeonMapLabels &dungeon_map_labels); + +absl::Status SaveDungeonMaps(Rom &rom, std::vector &dungeon_maps); + +absl::Status LoadDungeonMapTile16(gfx::Tilemap &tile16_blockset, Rom &rom, + const std::vector &gfx_data, bool bin_mode); +absl::Status SaveDungeonMapTile16(gfx::Tilemap &tile16_blockset, Rom &rom); + absl::Status LoadDungeonMapGfxFromBinary(Rom &rom, std::array &sheets, - gfx::Tilesheet &tile16_sheet, std::vector &gfx_bin_data); } // namespace zelda3