35 std::array<zelda3::Room, 0x128>& rooms) {
37 return absl::FailedPreconditionError(
"ROM not loaded");
40 constexpr int kTotalRooms = 0x100 + 40;
43 std::vector<std::pair<int, zelda3::RoomSize>> room_size_results;
44 std::vector<std::pair<int, ImVec4>> room_palette_results;
50 LOG_DEBUG(
"Dungeon",
"Loading %d dungeon rooms sequentially (WASM build)",
54 return absl::FailedPreconditionError(
"GameData not available");
60 app::platform::WasmLoadingManager::BeginLoading(
"Loading Dungeon Rooms");
62 for (
int i = 0; i < kTotalRooms; ++i) {
65 float progress =
static_cast<float>(i) /
static_cast<float>(kTotalRooms);
66 app::platform::WasmLoadingManager::UpdateProgress(loading_handle,
70 if (app::platform::WasmLoadingManager::IsCancelled(loading_handle)) {
71 app::platform::WasmLoadingManager::EndLoading(loading_handle);
72 return absl::CancelledError(
"Dungeon room loading cancelled by user");
83 auto palette_id =
rom_->
ReadWord(0xDEC4B + dungeon_palette_ptr);
84 if (palette_id.status() == absl::OkStatus()) {
85 int p_id = palette_id.value() / 180;
86 auto color = dungeon_man_pal_group[p_id][3];
87 room_size_results.emplace_back(i, room_size);
88 room_palette_results.emplace_back(rooms[i].palette(), color.rgb());
92 app::platform::WasmLoadingManager::EndLoading(loading_handle);
95 constexpr int kMaxConcurrency =
99 const int max_concurrency = std::min(
100 kMaxConcurrency,
static_cast<int>(std::thread::hardware_concurrency()));
101 const int rooms_per_thread =
102 (kTotalRooms + max_concurrency - 1) / max_concurrency;
105 "Loading %d dungeon rooms using %d threads (%d rooms per thread)",
106 kTotalRooms, max_concurrency, rooms_per_thread);
109 std::mutex results_mutex;
112 std::vector<std::future<absl::Status>> futures;
114 for (
int thread_id = 0; thread_id < max_concurrency; ++thread_id) {
115 auto task = [
this, &rooms, thread_id, rooms_per_thread, &results_mutex,
116 &room_size_results, &room_palette_results,
117 kTotalRooms]() -> absl::Status {
118 const int start_room = thread_id * rooms_per_thread;
119 const int end_room = std::min(start_room + rooms_per_thread, kTotalRooms);
122 return absl::FailedPreconditionError(
"GameData not available");
126 for (
int i = start_room; i < end_room; ++i) {
139 auto palette_id =
rom_->
ReadWord(0xDEC4B + dungeon_palette_ptr);
140 if (palette_id.status() == absl::OkStatus()) {
141 int p_id = palette_id.value() / 180;
142 auto color = dungeon_man_pal_group[p_id][3];
146 std::lock_guard<std::mutex> lock(results_mutex);
147 room_size_results.emplace_back(i, room_size);
148 room_palette_results.emplace_back(rooms[i].palette(), color.rgb());
153 return absl::OkStatus();
156 futures.emplace_back(std::async(std::launch::async, task));
160 for (
auto& future : futures) {
167 gfx::ScopedTimer postprocess_timer(
"DungeonRoomLoader::PostProcessResults");
170 std::sort(room_size_results.begin(), room_size_results.end(),
171 [](
const auto& a,
const auto& b) { return a.first < b.first; });
172 std::sort(room_palette_results.begin(), room_palette_results.end(),
173 [](
const auto& a,
const auto& b) { return a.first < b.first; });
176 for (
const auto& [room_id, room_size] : room_size_results) {
179 if (room_size.room_size_pointer != 0x0A8000) {
185 for (
const auto& [palette_id, color] : room_palette_results) {
191 return absl::OkStatus();
213 std::map<int, std::vector<int>> rooms_by_bank;
215 int bank = room.second >> 16;
216 rooms_by_bank[bank].push_back(room.second);
220 for (
auto& bank_rooms : rooms_by_bank) {
221 std::ranges::sort(bank_rooms.second);
223 for (
size_t i = 0; i < bank_rooms.second.size(); ++i) {
224 int room_ptr = bank_rooms.second[i];
230 return entry.second == room_ptr;
233 if (room_ptr != 0x0A8000) {
234 if (i < bank_rooms.second.size() - 1) {
235 room_sizes_[room_id] = bank_rooms.second[i + 1] - room_ptr;
237 int bank_end_address = (bank_rooms.first << 16) | 0xFFFF;
238 room_sizes_[room_id] = bank_end_address - room_ptr + 1;