65 ImGui::TextDisabled(
"Shared usage unavailable.");
70 ImGui::TextWrapped(
"Shared usage unavailable: %s",
71 std::string(usage.status().message()).c_str());
74 const auto summary = absl::StrFormat(
75 "Shared by %d room%s and %d map screen%s", usage->rooms.size(),
76 usage->rooms.size() == 1 ?
"" :
"s", usage->ow_areas.size(),
77 usage->ow_areas.size() == 1 ?
"" :
"s");
78 ImGui::TextWrapped(
"%s", summary.c_str());
79 if (usage->unscanned_rooms || usage->unscanned_ow_areas) {
81 "Incomplete scan: %d rooms / %d map screens unavailable.",
82 usage->unscanned_rooms, usage->unscanned_ow_areas);
84 const bool expanded = ImGui::TreeNode(
"Shared assignment details");
88 ImGui::TextWrapped(
"%s", usage->uses_live_overworld
89 ?
"Includes unsaved room and map selections."
90 :
"Includes unsaved room selections; maps read "
91 "from ROM until the overworld is loaded.");
93 "Map screens include large-map children. Zero inherits "
94 "each room or map's main group.");
95 if (ImGui::BeginChild(
"##SharedRoomGraphicsUsage", ImVec2(0, 150),
true)) {
96 const auto draw_ids = [](
const char* label,
const std::vector<int>& ids,
98 const auto title = absl::StrFormat(
"%s (%d)", label, ids.size());
99 ImGui::TextWrapped(
"%s", title.c_str());
101 ImGui::TextDisabled(
"None");
105 for (
const int id : ids) {
108 text += absl::StrFormat(
"%0*X", digits,
id);
110 ImGui::TextWrapped(
"%s", text.c_str());
112 draw_ids(
"Rooms using this assignment", usage->rooms, 3);
113 draw_ids(
"Map screens using this assignment", usage->ow_areas, 2);
114 draw_ids(
"Map references overridden by custom sheets",
115 usage->overridden_ow_areas, 2);
116 draw_ids(
"Map references using a separate ROM table",
117 usage->independent_ow_areas, 2);
178 std::vector<gfx::SnesColor> colors;
180 if (rendered.size() < 16) {
181 ImGui::TextWrapped(
"Load the room palette to preview replacement sheets.");
185 for (
int index = 0; index < 8; ++index) {
186 const auto color = rendered[index == 0 ? 0 : half + index];
187 colors.emplace_back(color.r, color.g, color.b);
190 "Preview: room palette row 0. Select a sheet, then apply.");
192 if (ImGui::Button(
"Apply to shared group")) {
203 if (ImGui::BeginChild(
"##RoomSheetPicker", ImVec2(0, 220),
true)) {
204 std::vector<int> candidates;
206 if (data->sheet_store.HasSheet(
id) &&
209 candidates.push_back(
id);
211 ImGuiListClipper clipper;
212 clipper.Begin(
static_cast<int>(candidates.size()), 54.0f);
213 while (clipper.Step()) {
214 for (
int row = clipper.DisplayStart; row < clipper.DisplayEnd; ++row) {
215 const int id = candidates[row];
217 const auto pixels = data->sheet_store.Sheet(
id);
218 const std::vector<uint8_t> current(pixels.begin(), pixels.end());
219 if (!preview.is_active() || preview.vector() != current) {
220 preview.Create(128, 32, 8, current);
223 if (preview.texture())
224 preview.UpdateTexture();
226 preview.CreateTexture();
227 const auto position = ImGui::GetCursorScreenPos();
228 const auto label = absl::StrFormat(
"Sheet %02X##replacement",
id);
234 absl::StrFormat(
"Sheet %02X",
id));
235 if (preview.texture()) {
236 ImGui::GetWindowDrawList()->AddImage(
237 (ImTextureID)preview.texture(),
238 ImVec2(position.x + 84, position.y + 8),
239 ImVec2(position.x + 212, position.y + 40), ImVec2(0, 0),
240 ImVec2(1, 1), ImGui::GetColorU32(ImVec4(1, 1, 1, 1)));
250 const auto blocks = room.
blocks();
259 if (!needs_refresh) {
262 needs_refresh =
true;
267 if (!needs_refresh) {
271 std::vector<SDL_Color> palette_colors;
272 if (SDL_Surface* bg_surface = room.
bg1_buffer().bitmap().surface()) {
274 palette_colors.assign(palette->colors,
275 palette->colors + palette->ncolors);
280 constexpr size_t kSheetBytes = 128 * 32;
283 const size_t offset = i * kSheetBytes;
286 meta.block_id = blocks[i];
287 meta.source_offset = offset;
288 if (offset + kSheetBytes > gfx_buffer.size()) {
294 std::vector<uint8_t> sheet_pixels(
295 gfx_buffer.begin() + offset, gfx_buffer.begin() + offset + kSheetBytes);
296 meta.nonzero_pixels =
static_cast<int>(
297 std::count_if(sheet_pixels.begin(), sheet_pixels.end(),
298 [](uint8_t value) { return value != 0; }));
302 if (!palette_colors.empty()) {
317 meta.palette_colors =
static_cast<int>(palette_colors.size());
331 ImGui::TextDisabled(
"Room graphics session closed.");
340 rooms_ = &ctx.editor->rooms();
344 return editor->EditRoomGraphicsSheet(room, slot, sheet);
347 return editor->GetRoomGraphicsUsage(roomset);
353 ImGui::TextDisabled(tr(
"No room data available"));
358 if (active_room_id < 0 ||
359 active_room_id >=
static_cast<int>(
rooms_->
size())) {
360 ImGui::TextDisabled(tr(
"Invalid room ID: %d"), active_room_id);
364 auto& room = (*rooms_)[active_room_id];
376 room.PrepareForRender();
382 auto blocks = room.blocks();
384 constexpr int kBlockWidth = 128;
385 constexpr int kBlockHeight = 32;
386 constexpr int kPreferredBlocksPerRow = 2;
387 constexpr float kPadding = 4.0f;
389 const int block_count =
static_cast<int>(blocks.size());
390 ImGui::Text(tr(
"Room %03X Graphics Blocks"), active_room_id);
391 ImGui::TextDisabled(tr(
"Main %02X | Room %02X | Sprites %02X | Palette %02X"),
392 room.resolved_main_blockset(), room.blockset(),
393 room.spriteset(), room.palette());
395 const auto patterns = asset_manager.GetTilePatterns();
396 if (!patterns.ok()) {
397 ImGui::TextWrapped(
"%s", patterns.status().ToString().c_str());
398 }
else if (*patterns) {
399 ImGui::TextWrapped(
"%s", tr(
"Standard object patterns: source file"));
400 ImGui::TextWrapped(
"%s", (*patterns)->source_path.c_str());
401 ImGui::TextDisabled(tr(
"%zu tile words; ROM bytes unchanged"),
402 (*patterns)->words.size());
404 if (!patterns.ok() || *patterns) {
406 asset_manager.ReloadAll();
413 const float available_width = ImGui::GetContentRegionAvail().x;
417 available_width, kBlockWidth, kBlockHeight, block_count,
420 const ImVec2 canvas_size(
421 std::max(available_width, sheet_layout.
content_width + kPadding * 2.0f),
423 ((block_count + sheet_layout.
columns - 1) / sheet_layout.
columns) *
424 ImGui::GetTextLineHeightWithSpacing());
434 ImGui::SetNextItemAllowOverlap();
437 const float grid_width = sheet_layout.
content_width + kPadding * 2.0f;
438 const float x_offset = std::max(0.0f, (canvas_size.x - grid_width) * 0.5f);
439 ImDrawList* draw_list = ImGui::GetWindowDrawList();
440 for (
int i = 0; i < block_count; ++i) {
441 const uint8_t block_id = blocks[
static_cast<size_t>(i)];
442 const int row = i / sheet_layout.
columns;
443 const int col = i % sheet_layout.
columns;
444 const ImVec2 local_pos(
445 x_offset + kPadding + col * (sheet_layout.
item_width + kPadding),
446 kPadding + row * (sheet_layout.
item_height + kPadding +
447 ImGui::GetTextLineHeightWithSpacing()));
465 const ImVec2 screen_pos(zero.x + local_pos.x, zero.y + local_pos.y);
466 const ImVec2 screen_end(screen_pos.x + sheet_layout.
item_width * scale,
468 draw_list->AddRect(screen_pos, screen_end,
470 draw_list->AddText(ImVec2(screen_pos.x + 6.0f, screen_pos.y + 6.0f),
472 block_id == 0 ?
"Empty" :
"Missing");
475 const ImVec2 start(zero.x + local_pos.x, zero.y + local_pos.y);
476 const ImVec2 end(start.x + sheet_layout.
item_width,
478 const auto saved_cursor = ImGui::GetCursorScreenPos();
479 ImGui::SetCursorScreenPos(start);
481 if (ImGui::InvisibleButton(
484 ImGuiButtonFlags_EnableNav)) {
491 draw_list->AddRect(start, end, ImGui::GetColorU32(ImGuiCol_NavHighlight),
493 const char* role = i < 3 ?
"Main"
495 : i == 7 ?
"Main/anim"
496 : i < 12 ?
"Fixed sprite"
498 const auto label = absl::StrFormat(
"%02d %s / %02X", i, role, block_id);
499 draw_list->AddText(ImVec2(start.x, end.y),
500 ImGui::GetColorU32(ImGuiCol_Text), label.c_str());
502 ImGui::SetCursorScreenPos(saved_cursor);
510 ImGuiTreeNodeFlags_DefaultOpen)) {
511 ImGui::TextDisabled(tr(
512 "Source: Room::get_gfx_buffer() -> preview bitmap -> queued texture"));
513 ImGui::TextDisabled(tr(
"Room buffer bytes: %zu"),
514 room.get_gfx_buffer().size());
517 i < std::min(block_count,
521 const uintptr_t texture_value =
reinterpret_cast<uintptr_t
>(
525 tr(
"Slot %02d | Block %02X | Buf +0x%04zX | %dx%d | nz=%d | pal=%d | "
526 "active=%d surf=%d tex=%d (0x%zx)"),
527 i, meta.block_id, meta.source_offset, meta.width, meta.height,
528 meta.nonzero_pixels, meta.palette_colors, meta.bitmap_active,
529 meta.has_surface, meta.has_texture, texture_value);
void RefreshSheetPreviews(const zelda3::Room &room)
std::map< int, gfx::Bitmap > picker_previews_
void DrawAssignmentControls(const zelda3::Room &room)
void DrawAssignmentPicker(const zelda3::Room &room)
void Draw(bool *p_open) override
Draw the panel content.
std::array< gfx::Bitmap, 16 > sheet_previews_
std::array< SheetPreviewMetadata, 16 > sheet_preview_metadata_
AdaptiveSheetGridLayout ResolveAdaptiveSheetGridLayout(float available_width, int source_item_width, int source_item_height, int item_count, int preferred_columns=2, AdaptiveSheetScaleMode mode=AdaptiveSheetScaleMode::kFit, float min_scale=0.35f, float max_scale=4.0f, float gap=4.0f, float horizontal_chrome=24.0f)