46 ImGui::SetNextWindowPos(
48 ImGuiCond_FirstUseEver);
49 ImGui::SetNextWindowSize(ImVec2(300, 0), ImGuiCond_FirstUseEver);
51 ImGuiWindowFlags_NoCollapse)) {
52 ImGui::Text(tr(
"Room: 0x%03X (%d)"), room_id, room_id);
54 ImGui::Text(tr(
"Graphics"));
55 ImGui::Text(tr(
" Blockset: 0x%02X"), room.
blockset());
56 ImGui::Text(tr(
" Palette: 0x%02X"), room.
palette());
57 ImGui::Text(tr(
" Layout: 0x%02X"), room.
layout_id());
58 ImGui::Text(tr(
" Spriteset: 0x%02X"), room.
spriteset());
60 ImGui::Text(tr(
"Content"));
62 ImGui::Text(tr(
" Sprites: %zu"), room.
GetSprites().size());
64 ImGui::Text(tr(
"Buffers"));
67 ImGui::Text(tr(
" BG1: %dx%d %s"), bg1.width(), bg1.height(),
68 bg1.texture() ?
"(has texture)" :
"(NO TEXTURE)");
69 ImGui::Text(tr(
" BG2: %dx%d %s"), bg2.width(), bg2.height(),
70 bg2.texture() ?
"(has texture)" :
"(NO TEXTURE)");
72 ImGui::Text(tr(
"Layers (4-way)"));
78 if (ImGui::Checkbox(tr(
"BG1 Layout"), &bg1l)) {
81 if (ImGui::Checkbox(tr(
"BG1 Objects"), &bg1o)) {
84 if (ImGui::Checkbox(tr(
"BG2 Layout"), &bg2l)) {
87 if (ImGui::Checkbox(tr(
"BG2 Objects"), &bg2o)) {
90 int blend =
static_cast<int>(
92 if (ImGui::SliderInt(tr(
"BG2 Blend"), &blend, 0, 4)) {
100 ImGui::Text(tr(
"Layout Override"));
101 static bool enable_override =
false;
102 ImGui::Checkbox(tr(
"Enable Override"), &enable_override);
103 if (enable_override) {
110 ImGui::Text(tr(
"Preview State"));
111 if (
auto* editor_state =
113 editor_state !=
nullptr) {
114 bool preview_state_changed =
false;
116 bool water_face_active = editor_state->IsWaterFaceActive(room_id);
117 if (ImGui::Checkbox(tr(
"Water Face Active"), &water_face_active)) {
118 editor_state->SetWaterFaceActive(room_id, water_face_active);
119 preview_state_changed =
true;
122 bool dam_floodgate_open = editor_state->IsDamFloodgateOpen(room_id);
123 if (ImGui::Checkbox(tr(
"Dam Floodgate Open"), &dam_floodgate_open)) {
124 editor_state->SetDamFloodgateOpen(room_id, dam_floodgate_open);
125 preview_state_changed =
true;
128 bool wall_moved = editor_state->IsWallMoved(room_id);
129 if (ImGui::Checkbox(tr(
"Moving Wall Shifted"), &wall_moved)) {
130 editor_state->SetWallMoved(room_id, wall_moved);
131 preview_state_changed =
true;
134 bool floor_bombed = editor_state->IsFloorBombable(room_id);
135 if (ImGui::Checkbox(tr(
"Bombed Floor Open"), &floor_bombed)) {
136 editor_state->SetFloorBombable(room_id, floor_bombed);
137 preview_state_changed =
true;
142 bool blind_light_active =
143 editor_state->IsFloorBombable(kThievesTownEastAtticRoomId);
144 if (ImGui::Checkbox(tr(
"East Attic Open / Blind Light"),
145 &blind_light_active)) {
146 editor_state->SetFloorBombable(kThievesTownEastAtticRoomId,
148 preview_state_changed =
true;
150 if (ImGui::IsItemHovered()) {
151 ImGui::SetTooltip(tr(
152 "Object FF1 uses the persisted bombed-floor flag for room 0x065, "
153 "even when previewed in Blind's room."));
156 bool rupee_floor_cleared = editor_state->IsRupeeFloorCleared(room_id);
157 if (ImGui::Checkbox(tr(
"Rupee Floor Cleared"), &rupee_floor_cleared)) {
158 editor_state->SetRupeeFloorCleared(room_id, rupee_floor_cleared);
159 preview_state_changed =
true;
162 if (ImGui::Button(tr(
"Reset Preview State"))) {
163 editor_state->Reset();
164 preview_state_changed =
true;
167 if (preview_state_changed) {
172 tr(
"Preview state controls require EditorDungeonState."));
177 ImGui::Text(tr(
"Object Outline Filters"));
178 ImGui::Text(tr(
"By Type:"));
179 ImGui::Checkbox(tr(
"Type 1"),
181 ImGui::Checkbox(tr(
"Type 2"),
183 ImGui::Checkbox(tr(
"Type 3"),
185 ImGui::Text(tr(
"By Stored Placement:"));
186 ImGui::Checkbox(tr(
"Primary / Upper layer (BG1)"),
188 ImGui::Checkbox(tr(
"BG2 overlay / Lower layer (BG2)"),
190 ImGui::Checkbox(tr(
"BG1 overlay (room stream only)"),
294 const float scale = transform.
scale();
302 ImGui::GetWindowDrawList(), room_origin, scale,
310 ImGui::GetWindowDrawList(), room_origin, scale, room);
315 room_origin, scale, room);
320 ImGui::GetWindowDrawList(), room_origin, scale, room);
325 ImGui::GetWindowDrawList(), room_origin, scale, room,
331 ImGui::GetWindowDrawList(), room_origin, scale, room,
337 ImGui::GetWindowDrawList(), room_origin, scale,
342 ImDrawList* draw_list = ImGui::GetWindowDrawList();
343 const ImVec2 canvas_pos = room_origin;
345 const ImU32 fill_color =
346 ImGui::GetColorU32(ImVec4(info.x, info.y, info.z, 0.25f));
347 const ImU32 border_color =
348 ImGui::GetColorU32(ImVec4(info.x, info.y, info.z, 0.8f));
349 const ImU32 text_bg_color = ImGui::GetColorU32(ImVec4(0, 0, 0, 0.6f));
351 auto is_custom = [](
int id) {
356 if (!is_custom(
static_cast<int>(obj.id_))) {
360 const float px =
static_cast<float>(obj.x()) * 8.0f * scale;
361 const float py =
static_cast<float>(obj.y()) * 8.0f * scale;
362 const float box_w = 16.0f * scale;
363 const float box_h = 16.0f * scale;
364 const ImVec2 p0(canvas_pos.x + px, canvas_pos.y + py);
365 const ImVec2 p1(p0.x + box_w, p0.y + box_h);
367 draw_list->AddRectFilled(p0, p1, fill_color, 2.0f);
368 draw_list->AddRect(p0, p1, border_color, 2.0f, 0, 1.5f);
371 std::snprintf(label,
sizeof(label),
"0x%02X s%d",
372 static_cast<int>(obj.id_),
373 static_cast<int>(obj.size_ & 0x1F));
374 const ImVec2 text_sz = ImGui::CalcTextSize(label);
375 const ImVec2 tp(p0.x + 1.0f, p0.y - text_sz.y - 1.0f);
376 draw_list->AddRectFilled(
377 tp, ImVec2(tp.x + text_sz.x + 2.0f, tp.y + text_sz.y), text_bg_color,
379 draw_list->AddText(tp, border_color, label);
384 const bool show_tracks =
387 if (show_tracks && !tracks.empty()) {
388 ImDrawList* draw_list = ImGui::GetWindowDrawList();
389 const ImVec2 canvas_pos = room_origin;
391 const int active_track =
396 for (
const auto& track : tracks) {
398 if (track.room_id != room_id || !local) {
402 ImVec4 marker_color = theme.selection_primary;
403 if (track.id == active_track) {
404 marker_color = theme.status_warning;
407 const float px =
static_cast<float>(local->first + 8) * scale;
408 const float py =
static_cast<float>(local->second + 8) * scale;
409 ImVec2 center(canvas_pos.x + px, canvas_pos.y + py);
410 const float radius = 6.0f * scale;
412 draw_list->AddCircleFilled(center, radius,
413 ImGui::GetColorU32(marker_color));
414 draw_list->AddCircle(center, radius + 2.0f,
415 ImGui::GetColorU32(ImVec4(0, 0, 0, 0.6f)), 0,
418 std::string label = absl::StrFormat(
"T%d", track.id);
420 ImVec2(center.x + 8.0f * scale, center.y - 6.0f * scale),
421 ImGui::GetColorU32(theme.text_primary), label.c_str());
429 const int room_base_x = (room_id & 0x0F) * 0x200;
430 const int room_base_y = (room_id >> 4) * 0x200;
431 const float camera_x =
432 static_cast<float>(
static_cast<int>(camera.camera_x) - room_base_x);
433 const float camera_y =
434 static_cast<float>(
static_cast<int>(camera.camera_y) - room_base_y);
435 const float player_x =
436 static_cast<float>(
static_cast<int>(camera.player_x) - room_base_x);
437 const float player_y =
438 static_cast<float>(
static_cast<int>(camera.player_y) - room_base_y);
439 ImDrawList* draw_list = ImGui::GetWindowDrawList();
442 const ImVec4 diagnostic_color =
443 !validation.geometry_valid() ? theme.status_error
444 : !validation.matches_derived() ? theme.status_warning
445 : theme.selection_primary;
446 const ImU32 camera_fill = ImGui::GetColorU32(ImVec4(
447 diagnostic_color.x, diagnostic_color.y, diagnostic_color.z, 0.10f));
448 const ImU32 camera_border = ImGui::GetColorU32(ImVec4(
449 diagnostic_color.x, diagnostic_color.y, diagnostic_color.z, 0.90f));
450 const ImU32 marker_color = ImGui::GetColorU32(theme.status_warning);
451 const ImVec2 room_max(room_origin.x + 512.0f * scale,
452 room_origin.y + 512.0f * scale);
453 const ImVec2 camera_min(room_origin.x + camera_x * scale,
454 room_origin.y + camera_y * scale);
455 const ImVec2 camera_max(camera_min.x + 256.0f * scale,
456 camera_min.y + 224.0f * scale);
457 const ImVec2 player(room_origin.x + player_x * scale,
458 room_origin.y + player_y * scale);
459 draw_list->PushClipRect(room_origin, room_max,
true);
460 draw_list->AddRectFilled(camera_min, camera_max, camera_fill);
461 draw_list->AddRect(camera_min, camera_max, camera_border, 0.0f, 0,
462 std::max(1.0f, 2.0f * scale));
463 const float marker_radius = std::max(4.0f, 6.0f * scale);
464 draw_list->AddCircleFilled(player, marker_radius, marker_color);
465 draw_list->AddCircle(player, marker_radius + 2.0f,
466 ImGui::GetColorU32(ImVec4(0, 0, 0, 0.8f)), 0, 2.0f);
467 const std::string label = absl::StrFormat(
469 camera.quadrant, validation.matches_derived() ?
"" :
" · check");
470 draw_list->AddText(ImVec2(camera_min.x + 4.0f, camera_min.y + 3.0f),
471 camera_border, label.c_str());
472 const std::string boundaries = absl::StrFormat(
473 "N %02X/%02X E %02X/%02X S %02X/%02X W %02X/%02X",
474 camera.boundaries[0], camera.boundaries[1], camera.boundaries[6],
475 camera.boundaries[7], camera.boundaries[2], camera.boundaries[3],
476 camera.boundaries[4], camera.boundaries[5]);
477 draw_list->AddText(ImVec2(camera_min.x + 4.0f,
478 camera_max.y - ImGui::GetTextLineHeight() - 3.0f),
479 camera_border, boundaries.c_str());
480 draw_list->PopClipRect();