13#include "imgui/imgui.h"
20using ImGui::BeginTable;
22using ImGui::Separator;
23using ImGui::TableNextColumn;
29 int& current_world,
int& current_map,
bool& current_map_lock,
30 bool& show_map_properties_panel,
bool& show_custom_bg_color_editor,
31 bool& show_overlay_editor,
bool& show_overlay_preview,
int& game_state,
33 (void)show_overlay_editor;
34 (void)show_custom_bg_color_editor;
36 (void)show_overlay_preview;
39 if (BeginTable(
"CanvasToolbar", 7,
40 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit,
42 ImGui::TableSetupColumn(
"World", ImGuiTableColumnFlags_WidthFixed,
44 ImGui::TableSetupColumn(
"Map", ImGuiTableColumnFlags_WidthFixed,
46 ImGui::TableSetupColumn(
"Area Size", ImGuiTableColumnFlags_WidthFixed,
48 ImGui::TableSetupColumn(
"Lock", ImGuiTableColumnFlags_WidthFixed,
50 ImGui::TableSetupColumn(
"Mode", ImGuiTableColumnFlags_WidthFixed,
52 ImGui::TableSetupColumn(
"Entity", ImGuiTableColumnFlags_WidthStretch);
53 ImGui::TableSetupColumn(
"Sidebar", ImGuiTableColumnFlags_WidthFixed, 40.0f);
57 ImGui::Combo(
"##world", ¤t_world,
kWorldNames, 3);
60 ImGui::Text(
"%d (0x%02X)", current_map, current_map);
67 int current_area_size =
73 if (ImGui::Combo(
"##AreaSize", ¤t_area_size,
kAreaSizeNames, 4)) {
83 const char* limited_names[] = {
"Small (1x1)",
"Large (2x2)"};
84 int limited_size = (current_area_size == 0 || current_area_size == 1)
88 if (ImGui::Combo(
"##AreaSize", &limited_size, limited_names, 2)) {
101 HOVER_HINT(
"Small (1x1) and Large (2x2) maps. Wide/Tall require v3+");
108 current_map_lock = !current_map_lock;
110 HOVER_HINT(current_map_lock ?
"Unlock Map" :
"Lock Map");
114 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
119 HOVER_HINT(
"Mouse Mode (1)\nNavigate, pan, and manage entities");
126 HOVER_HINT(
"Tile Paint Mode (2)\nDraw tiles on the map");
127 ImGui::PopStyleVar();
132 const char* entity_icon =
"";
133 const char* entity_label =
"";
134 switch (entity_edit_mode) {
143 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f),
"%s %s", entity_icon, entity_label);
149 show_map_properties_panel = !show_map_properties_panel;
158 int current_map,
bool& show_map_properties_panel) {
159 (void)show_map_properties_panel;
161 Text(
"No overworld loaded");
167 Text(
"Current Map: %d (0x%02X)", current_map, current_map);
173 if (ImGui::BeginTabBar(
"MapPropertiesTabs",
174 ImGuiTabBarFlags_FittingPolicyScroll)) {
176 if (ImGui::BeginTabItem(
"Basic Properties")) {
182 if (ImGui::BeginTabItem(
"Sprite Properties")) {
190 ImGui::BeginTabItem(
"Custom Features")) {
196 if (ImGui::BeginTabItem(
"Tile Graphics")) {
202 if (ImGui::BeginTabItem(
"Music")) {
212 int current_map,
bool& show_custom_bg_color_editor) {
213 (void)show_custom_bg_color_editor;
215 Text(
"No overworld loaded");
221 Text(
"Custom background colors require ZSCustomOverworld v2+");
225 Text(
"Custom Background Color Editor");
229 bool use_area_specific_bg_color =
231 if (ImGui::Checkbox(
"Use Area-Specific Background Color",
232 &use_area_specific_bg_color)) {
235 use_area_specific_bg_color ? 0x01 : 0x00;
238 if (use_area_specific_bg_color) {
240 uint16_t current_color =
247 if (ImGui::ColorPicker4(
248 "Background Color", (
float*)&color_vec,
249 ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHex)) {
253 ->set_area_specific_bg_color(new_snes_color.
snes());
258 (*rom_)[rom_address] = new_snes_color.
snes() & 0xFF;
259 (*rom_)[rom_address + 1] = (new_snes_color.
snes() >> 8) & 0xFF;
262 Text(
"SNES Color: 0x%04X", current_color);
267 bool& show_overlay_editor) {
268 (void)show_overlay_editor;
270 Text(
"No overworld loaded");
276 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f),
278 ImGui::Text(
"Map: 0x%02X", current_map);
282 ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.4f, 1.0f),
ICON_MD_INFO
283 " Enhanced overlay editing requires ZSCustomOverworld v1+");
286 "Subscreen overlays are a vanilla feature used for atmospheric effects "
287 "like fog, rain, and forest canopy. ZSCustomOverworld expands this by "
288 "allowing per-area overlay configuration and additional customization.");
294 ImGuiTreeNodeFlags_DefaultOpen)) {
297 "Visual effects (subscreen overlays) are semi-transparent layers drawn "
298 "on top of or behind your map. They reference special area maps "
300 "for their tile16 graphics data.");
302 ImGui::Text(
"Common uses:");
303 ImGui::BulletText(
"Fog effects (Lost Woods, Skull Woods)");
304 ImGui::BulletText(
"Rain (Misery Mire)");
305 ImGui::BulletText(
"Forest canopy (Lost Woods)");
306 ImGui::BulletText(
"Sky backgrounds (Death Mountain)");
307 ImGui::BulletText(
"Under bridge views");
313 bool use_subscreen_overlay =
316 &use_subscreen_overlay)) {
319 use_subscreen_overlay ? 0x01 : 0x00;
321 if (ImGui::IsItemHovered()) {
322 ImGui::SetTooltip(
"Enable/disable visual effect overlay for this map area");
325 if (use_subscreen_overlay) {
327 uint16_t current_overlay =
332 ->set_subscreen_overlay(current_overlay);
337 (*rom_)[rom_address] = current_overlay & 0xFF;
338 (*rom_)[rom_address + 1] = (current_overlay >> 8) & 0xFF;
340 if (ImGui::IsItemHovered()) {
342 "ID of the special area map (0x80-0x9F) to use for\n"
343 "visual effects. That map's tile16 data will be drawn\n"
344 "as a semi-transparent layer on this area.");
349 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
ICON_MD_INFO " %s",
350 overlay_desc.c_str());
354 " Common Visual Effect IDs")) {
356 ImGui::BulletText(
"0x0093 - Triforce Room Curtain");
357 ImGui::BulletText(
"0x0094 - Under the Bridge");
358 ImGui::BulletText(
"0x0095 - Sky Background (LW Death Mountain)");
359 ImGui::BulletText(
"0x0096 - Pyramid Background");
360 ImGui::BulletText(
"0x0097 - Fog Overlay (Master Sword Area)");
361 ImGui::BulletText(
"0x009C - Lava Background (DW Death Mountain)");
362 ImGui::BulletText(
"0x009D - Fog Overlay (Lost/Skull Woods)");
363 ImGui::BulletText(
"0x009E - Tree Canopy (Forest)");
364 ImGui::BulletText(
"0x009F - Rain Effect (Misery Mire)");
365 ImGui::BulletText(
"0x00FF - No Overlay (Disabled)");
370 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
ICON_MD_BLOCK
371 " No visual effects enabled for this area");
376 gui::Canvas& canvas,
int current_map,
bool current_map_lock,
377 bool& show_map_properties_panel,
bool& show_custom_bg_color_editor,
378 bool& show_overlay_editor,
int current_mode) {
396 entity_menu.
subitems.push_back(entrance_item);
406 entity_menu.
subitems.push_back(hole_item);
416 entity_menu.
subitems.push_back(exit_item);
426 entity_menu.
subitems.push_back(item_item);
436 entity_menu.
subitems.push_back(sprite_item);
444 tile16_edit_item.
callback = [
this]() {
455 lock_item.
label = current_map_lock ?
"Unlock Map" :
"Lock to This Map";
456 lock_item.
callback = [¤t_map_lock]() {
457 current_map_lock = !current_map_lock;
464 properties_item.
callback = [&show_map_properties_panel]() {
465 show_map_properties_panel =
true;
475 bg_color_item.
callback = [&show_custom_bg_color_editor]() {
476 show_custom_bg_color_editor =
true;
483 overlay_item.
callback = [&show_overlay_editor]() {
484 show_overlay_editor =
true;
492 reset_view_item.
callback = [&canvas]() {
500 zoom_in_item.
callback = [&canvas]() {
509 zoom_out_item.
callback = [&canvas]() {
519 if (ImGui::BeginPopup(
523 ImGui::PushID(
"GraphicsPopup");
528 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
529 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(padding, padding));
531 ImGui::Text(
"Graphics Settings");
537 ->mutable_area_graphics(),
546 (*maps_bmp_)[current_map].set_modified(
true);
558 HOVER_HINT(
"Main tileset graphics for this map area");
565 ->mutable_sprite_graphics(game_state),
571 HOVER_HINT(
"Sprite graphics sheet for current game state");
577 ->mutable_animated_gfx(),
584 HOVER_HINT(
"Animated tile graphics (water, lava, etc.)");
595 if (BeginTable(
"CustomTileGraphics", 2, ImGuiTableFlags_SizingFixedFit)) {
596 for (
int i = 0; i < 8; i++) {
598 std::string label = absl::StrFormat(
ICON_MD_LAYERS " Sheet %d", i);
601 ->mutable_custom_tileset(i),
608 if (ImGui::IsItemHovered()) {
609 ImGui::SetTooltip(
"Custom graphics sheet %d (0x00-0xFF)", i);
616 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
619 "Custom tile graphics require ZSCustomOverworld v1+.\n"
620 "Upgrade your ROM to access 8 customizable graphics sheets.");
623 ImGui::PopStyleVar(2);
630 bool& show_custom_bg_color_editor) {
631 if (ImGui::BeginPopup(
635 ImGui::PushID(
"PalettesPopup");
640 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
641 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(padding, padding));
643 ImGui::Text(
"Palette Settings");
649 ->mutable_area_palette(),
655 HOVER_HINT(
"Main color palette for background tiles");
663 ->mutable_main_palette(),
669 HOVER_HINT(
"Extended main palette (ZSCustomOverworld v2+)");
677 ->mutable_sprite_palette(game_state),
682 HOVER_HINT(
"Color palette for sprites in current game state");
687 show_custom_bg_color_editor = !show_custom_bg_color_editor;
689 HOVER_HINT(
"Open custom background color editor (v2+)");
691 ImGui::PopStyleVar(2);
698 bool& show_map_properties_panel,
699 bool& show_overlay_preview,
701 if (ImGui::BeginPopup(
705 ImGui::PushID(
"ConfigPopup");
710 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
711 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(padding, padding));
717 if (BeginTable(
"BasicProps", 2, ImGuiTableFlags_SizingFixedFit)) {
724 ->mutable_message_id(),
729 if (ImGui::IsItemHovered()) {
730 ImGui::SetTooltip(
"Message ID shown when entering this area");
742 if (ImGui::IsItemHovered()) {
744 "Affects sprite graphics/palettes based on story progress");
758 int current_area_size =
762 if (asm_version >= 3 && asm_version != 0xFF) {
773 HOVER_HINT(
"Map area size (1x1, 2x2, 2x1, 1x2 screens)");
776 const char* limited_names[] = {
"Small (1x1)",
"Large (2x2)"};
777 int limited_size = (current_area_size == 0 || current_area_size == 1)
791 HOVER_HINT(
"Small (1x1) and Large (2x2) maps. Wide/Tall require v3+");
806 show_map_properties_panel =
true;
807 ImGui::CloseCurrentPopup();
809 HOVER_HINT(
"Open detailed area configuration with all settings tabs");
811 ImGui::PopStyleVar(2);
818 if (BeginTable(
"BasicProperties", 2,
819 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
820 ImGui::TableSetupColumn(
"Property", ImGuiTableColumnFlags_WidthFixed, 180);
821 ImGui::TableSetupColumn(
"Value", ImGuiTableColumnFlags_WidthStretch);
828 ->mutable_area_graphics(),
832 (*maps_bmp_)[current_map].set_modified(
true);
838 if (ImGui::IsItemHovered()) {
839 ImGui::SetTooltip(
"Main tileset graphics for this map area");
847 ->mutable_area_palette(),
853 if (ImGui::IsItemHovered()) {
854 ImGui::SetTooltip(
"Color palette for background tiles");
862 ->mutable_message_id(),
867 if (ImGui::IsItemHovered()) {
868 ImGui::SetTooltip(
"Message displayed when entering this area");
880 if (ImGui::IsItemHovered()) {
881 ImGui::SetTooltip(
"Enable pixelated mosaic transition effect");
890 ->mutable_area_music(0),
894 if (ImGui::IsItemHovered()) {
895 ImGui::SetTooltip(
"Music track before rescuing Zelda");
903 ->mutable_area_music(1),
907 if (ImGui::IsItemHovered()) {
908 ImGui::SetTooltip(
"Music track after rescuing Zelda");
916 ->mutable_area_music(2),
920 if (ImGui::IsItemHovered()) {
921 ImGui::SetTooltip(
"Music track after obtaining Master Sword");
929 ->mutable_area_music(3),
933 if (ImGui::IsItemHovered()) {
934 ImGui::SetTooltip(
"Music track after defeating Agahnim (Dark World)");
942 if (BeginTable(
"SpriteProperties", 2,
943 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
944 ImGui::TableSetupColumn(
"Property", ImGuiTableColumnFlags_WidthFixed, 180);
945 ImGui::TableSetupColumn(
"Value", ImGuiTableColumnFlags_WidthStretch);
950 static int game_state = 0;
951 ImGui::SetNextItemWidth(120.f);
956 if (ImGui::IsItemHovered()) {
957 ImGui::SetTooltip(
"Affects which sprite graphics/palettes are used");
965 ->mutable_sprite_graphics(1),
970 if (ImGui::IsItemHovered()) {
971 ImGui::SetTooltip(
"First sprite graphics sheet for Zelda rescued state");
979 ->mutable_sprite_graphics(2),
984 if (ImGui::IsItemHovered()) {
986 "Second sprite graphics sheet for Master Sword obtained state");
994 ->mutable_sprite_palette(1),
999 if (ImGui::IsItemHovered()) {
1000 ImGui::SetTooltip(
"Color palette for sprites - Zelda rescued state");
1008 ->mutable_sprite_palette(2),
1013 if (ImGui::IsItemHovered()) {
1015 "Color palette for sprites - Master Sword obtained state");
1023 if (BeginTable(
"CustomFeatures", 2,
1024 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
1025 ImGui::TableSetupColumn(
"Property", ImGuiTableColumnFlags_WidthFixed, 180);
1026 ImGui::TableSetupColumn(
"Value", ImGuiTableColumnFlags_WidthStretch);
1034 int current_area_size =
1036 ImGui::SetNextItemWidth(130.f);
1040 static const char* all_sizes[] = {
"Small (1x1)",
"Large (2x2)",
1041 "Wide (2x1)",
"Tall (1x2)"};
1042 if (ImGui::Combo(
"##AreaSize", ¤t_area_size, all_sizes, 4)) {
1050 if (ImGui::IsItemHovered()) {
1052 "Map size: Small (1x1), Large (2x2), Wide (2x1), Tall (1x2)");
1056 static const char* limited_sizes[] = {
"Small (1x1)",
"Large (2x2)"};
1057 int limited_size = (current_area_size == 0 || current_area_size == 1)
1061 if (ImGui::Combo(
"##AreaSize", &limited_size, limited_sizes, 2)) {
1070 if (ImGui::IsItemHovered()) {
1072 "Map size: Small (1x1), Large (2x2). Wide/Tall require v3+");
1077 rom_version_basic)) {
1083 ->mutable_main_palette(),
1089 if (ImGui::IsItemHovered()) {
1090 ImGui::SetTooltip(
"Extended main palette (ZSCustomOverworld v2+)");
1095 rom_version_basic)) {
1101 ->mutable_animated_gfx(),
1106 if (ImGui::IsItemHovered()) {
1107 ImGui::SetTooltip(
"Animated tile graphics ID (water, lava, etc.)");
1115 ->mutable_subscreen_overlay(),
1120 if (ImGui::IsItemHovered()) {
1121 ImGui::SetTooltip(
"Visual effects overlay ID (fog, rain, backgrounds)");
1137 if (BeginTable(
"TileGraphics", 2,
1138 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
1139 ImGui::TableSetupColumn(
"Property", ImGuiTableColumnFlags_WidthFixed,
1141 ImGui::TableSetupColumn(
"Value", ImGuiTableColumnFlags_WidthStretch);
1143 for (
int i = 0; i < 8; i++) {
1149 ->mutable_custom_tileset(i),
1158 if (ImGui::IsItemHovered()) {
1159 ImGui::SetTooltip(
"Custom graphics sheet %d (0x00-0xFF)", i);
1168 "These 8 sheets allow custom tile graphics per map. "
1169 "Each sheet references a graphics ID loaded into VRAM.");
1172 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
1176 "Custom tile graphics are not available in vanilla ROMs.\n\n"
1177 "To enable this feature, upgrade your ROM to ZSCustomOverworld v1+, "
1178 "which provides 8 customizable graphics sheets per map for advanced "
1179 "tileset customization.");
1187 if (BeginTable(
"MusicSettings", 2,
1188 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
1189 ImGui::TableSetupColumn(
"Game State", ImGuiTableColumnFlags_WidthFixed,
1191 ImGui::TableSetupColumn(
"Music Track ID",
1192 ImGuiTableColumnFlags_WidthStretch);
1194 const char* music_state_names[] = {
1200 const char* music_descriptions[] = {
1201 "Music before rescuing Zelda from the castle",
1202 "Music after rescuing Zelda from Hyrule Castle",
1203 "Music after obtaining the Master Sword from the Lost Woods",
1204 "Music after defeating Agahnim (Dark World music)"};
1206 for (
int i = 0; i < 4; i++) {
1208 ImGui::Text(
"%s", music_state_names[i]);
1213 ->mutable_area_music(i),
1218 int music_address = 0;
1234 if (music_address > 0) {
1235 (*rom_)[music_address] =
1237 ->mutable_area_music(i);
1240 if (ImGui::IsItemHovered()) {
1241 ImGui::SetTooltip(
"%s", music_descriptions[i]);
1250 "Music tracks control the background music for different "
1251 "game progression states on this overworld map.");
1256 ImGuiTreeNodeFlags_DefaultOpen)) {
1258 ImGui::BulletText(
"0x02 - Overworld Theme");
1259 ImGui::BulletText(
"0x05 - Kakariko Village");
1260 ImGui::BulletText(
"0x07 - Lost Woods");
1261 ImGui::BulletText(
"0x09 - Dark World Theme");
1262 ImGui::BulletText(
"0x0F - Ganon's Tower");
1263 ImGui::BulletText(
"0x11 - Death Mountain");
1284 return absl::OkStatus();
1291 return absl::OkStatus();
1301 bool include_self) {
1312 int parent_id = map->parent();
1313 std::vector<int> siblings;
1315 switch (map->area_size()) {
1317 siblings = {parent_id, parent_id + 1, parent_id + 8, parent_id + 9};
1320 siblings = {parent_id, parent_id + 1};
1323 siblings = {parent_id, parent_id + 8};
1329 for (
int sibling : siblings) {
1332 if (sibling == map_index && !include_self) {
1337 (*maps_bmp_)[sibling].set_modified(
true);
1358 ImGui::Text(
"Mosaic Effects (per direction):");
1361 std::array<bool, 4> mosaic_expanded = current_map_ptr->mosaic_expanded();
1362 const char* direction_names[] = {
"North",
"South",
"East",
"West"};
1364 for (
int i = 0; i < 4; i++) {
1365 if (ImGui::Checkbox(direction_names[i], &mosaic_expanded[i])) {
1366 current_map_ptr->set_mosaic_expanded(i, mosaic_expanded[i]);
1372 if (ImGui::Checkbox(
1382 bool& show_overlay_preview) {
1386 bool is_special_overworld_map = (current_map >= 0x80 && current_map < 0xA0);
1388 if (is_special_overworld_map) {
1390 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f),
1391 ICON_MD_INFO " Special Area Map (0x%02X)", current_map);
1394 "This is a special area map (0x80-0x9F) used as a visual effect "
1395 "source. These maps provide the graphics data for subscreen overlays "
1396 "like fog, rain, forest canopy, and sky backgrounds that appear on "
1397 "normal maps (0x00-0x7F).");
1400 "You can edit the tile16 data here to customize how the visual effects "
1401 "appear when referenced by other maps.");
1407 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f),
1417 if (ImGui::BeginPopup(
1421 ImGui::Text(
ICON_MD_HELP " Understanding Overlay Types");
1424 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
ICON_MD_LAYERS
1425 " 1. Subscreen Overlays (Visual Effects)");
1427 ImGui::BulletText(
"Displayed as semi-transparent layers");
1428 ImGui::BulletText(
"Reference special area maps (0x80-0x9F)");
1429 ImGui::BulletText(
"Examples: fog, rain, forest canopy, sky");
1430 ImGui::BulletText(
"Purely visual - don't affect collision");
1434 ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.4f, 1.0f),
1437 ImGui::BulletText(
"Dynamic tile16 changes on the map");
1438 ImGui::BulletText(
"Used for bridges appearing, holes opening");
1439 ImGui::BulletText(
"Stored as tile16 ID arrays");
1440 ImGui::BulletText(
"Affect collision and interaction");
1441 ImGui::BulletText(
"Triggered by game events/progression");
1446 "Note: Subscreen overlays are what you configure here. "
1447 "Map overlays are event-driven and edited separately.");
1454 ImGui::Text(
ICON_MD_LAYERS " Subscreen Overlay (Visual Effects)");
1456 uint16_t current_overlay =
1461 ->set_subscreen_overlay(current_overlay);
1465 if (ImGui::IsItemHovered()) {
1467 "References a special area map (0x80-0x9F) for visual effects.\n"
1468 "The referenced map's tile16 data is drawn as a semi-transparent\n"
1469 "layer on top of or behind this area for atmospheric effects.");
1474 if (current_overlay == 0x00FF) {
1475 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
ICON_MD_CHECK " %s",
1476 overlay_desc.c_str());
1477 }
else if (current_overlay >= 0x80 && current_overlay < 0xA0) {
1478 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
1481 ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.4f, 1.0f),
1488 &show_overlay_preview)) {
1491 if (ImGui::IsItemHovered()) {
1493 "Shows a semi-transparent preview of the visual effect overlay\n"
1494 "drawn on top of the current map in the editor canvas.\n\n"
1495 "This preview shows how the subscreen overlay will appear in-game.");
1502 ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.4f, 1.0f),
1511 if (ImGui::BeginPopup(
1515 ImGui::Text(
ICON_MD_HELP " Map Overlays (Interactive Tile Changes)");
1518 "Map overlays are different from visual effect overlays. "
1519 "They contain tile16 data that dynamically replaces tiles on "
1520 "the map based on game events or progression.");
1522 ImGui::Text(
"Common uses:");
1523 ImGui::BulletText(
"Bridges appearing over water");
1524 ImGui::BulletText(
"Holes revealing secret passages");
1525 ImGui::BulletText(
"Rocks/bushes being moved");
1526 ImGui::BulletText(
"Environmental changes from story events");
1529 "These are triggered by game code and stored as separate "
1530 "tile data arrays in the ROM. ZSCustomOverworld v3+ provides "
1531 "extended control over these features.");
1537 if (current_map_ptr->has_overlay()) {
1538 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
1540 current_map_ptr->overlay_id());
1542 static_cast<int>(current_map_ptr->overlay_data().size()));
1543 ImGui::TextColored(ImVec4(0.8f, 0.8f, 0.4f, 1.0f),
1546 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
1554 ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f),
1556 ImGui::BulletText(
"Visual effects use maps 0x80-0x9F");
1557 ImGui::BulletText(
"Map overlays are read-only");
1559 const char* version_name =
1561 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
ICON_MD_UPGRADE " %s",
1563 ImGui::BulletText(
"Enhanced visual effect control");
1565 ImGui::BulletText(
"Extended overlay system");
1566 ImGui::BulletText(
"Custom area sizes support");
1573 if (overlay_id == 0x0093) {
1574 return "Triforce Room Curtain";
1575 }
else if (overlay_id == 0x0094) {
1576 return "Under the Bridge";
1577 }
else if (overlay_id == 0x0095) {
1578 return "Sky Background (LW Death Mountain)";
1579 }
else if (overlay_id == 0x0096) {
1580 return "Pyramid Background";
1581 }
else if (overlay_id == 0x0097) {
1582 return "First Fog Overlay (Master Sword Area)";
1583 }
else if (overlay_id == 0x009C) {
1584 return "Lava Background (DW Death Mountain)";
1585 }
else if (overlay_id == 0x009D) {
1586 return "Second Fog Overlay (Lost Woods/Skull Woods)";
1587 }
else if (overlay_id == 0x009E) {
1588 return "Tree Canopy (Forest)";
1589 }
else if (overlay_id == 0x009F) {
1590 return "Rain Effect (Misery Mire)";
1591 }
else if (overlay_id == 0x00FF) {
1592 return "No Overlay";
1594 return "Custom overlay";
1600 bool show_overlay_preview) {
1607 uint16_t overlay_id = 0x00FF;
1608 bool has_subscreen_overlay =
false;
1610 bool is_special_overworld_map = (current_map >= 0x80 && current_map < 0xA0);
1612 if (is_special_overworld_map) {
1620 has_subscreen_overlay = (overlay_id != 0x00FF);
1622 if (!has_subscreen_overlay)
1626 int overlay_map_index = -1;
1627 if (overlay_id >= 0x80 && overlay_id < 0xA0) {
1628 overlay_map_index = overlay_id;
1635 const auto& overlay_bitmap = (*maps_bmp_)[overlay_map_index];
1636 if (!overlay_bitmap.is_active() || !overlay_bitmap.texture())
1640 int current_map_x = current_map % 8;
1641 int current_map_y = current_map / 8;
1642 if (current_world == 1) {
1643 current_map_x = (current_map - 0x40) % 8;
1644 current_map_y = (current_map - 0x40) / 8;
1645 }
else if (current_world == 2) {
1646 current_map_x = (current_map - 0x80) % 8;
1647 current_map_y = (current_map - 0x80) / 8;
1655 bool is_background_overlay =
1656 (overlay_id == 0x0095 || overlay_id == 0x0096 || overlay_id == 0x009C);
1659 ImU32 overlay_color =
1660 is_background_overlay ? IM_COL32(255, 255, 255, 128)
1662 IM_COL32(255, 255, 255,
1667 (ImTextureID)(intptr_t)overlay_bitmap.texture(), ImVec2(map_x, map_y),
1670 ImVec2(0, 0), ImVec2(1, 1), overlay_color);
1674 if (ImGui::BeginPopup(
1678 ImGui::PushID(
"ViewPopup");
1683 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
1684 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(padding, padding));
1686 ImGui::Text(
"View Controls");
1709 ImGui::PopStyleVar(2);
1716 if (ImGui::BeginPopup(
1720 ImGui::PushID(
"QuickPopup");
1725 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
1726 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(padding, padding));
1728 ImGui::Text(
"Quick Access");
1750 HOVER_HINT(
"Lock/unlock current map (Ctrl+L)");
1752 ImGui::PopStyleVar(2);
RefreshCallback refresh_overworld_map_
std::array< gfx::Bitmap, zelda3::kNumOverworldMaps > * maps_bmp_
std::function< void()> edit_tile16_callback_
void RefreshMapProperties()
void SetupCanvasContextMenu(gui::Canvas &canvas, int current_map, bool current_map_lock, bool &show_map_properties_panel, bool &show_custom_bg_color_editor, bool &show_overlay_editor, int current_mode=0)
void DrawOverlayEditor(int current_map, bool &show_overlay_editor)
void DrawPropertiesPopup(int current_map, bool &show_map_properties_panel, bool &show_overlay_preview, int &game_state)
RefreshCallback refresh_map_properties_
void RefreshOverworldMap()
RefreshPaletteCallback refresh_tile16_blockset_
void DrawOverlayPreviewOnMap(int current_map, int current_world, bool show_overlay_preview)
void DrawMosaicControls(int current_map)
void DrawMapPropertiesPanel(int current_map, bool &show_map_properties_panel)
absl::Status RefreshTile16Blockset()
std::function< void(const std::string &) entity_insert_callback_)
void DrawSpritePropertiesTab(int current_map)
RefreshPaletteCallback refresh_map_palette_
void DrawMusicTab(int current_map)
void DrawBasicPropertiesTab(int current_map)
void DrawCustomFeaturesTab(int current_map)
void DrawPalettesPopup(int current_map, int game_state, bool &show_custom_bg_color_editor)
void DrawCustomBackgroundColorEditor(int current_map, bool &show_custom_bg_color_editor)
void DrawCanvasToolbar(int ¤t_world, int ¤t_map, bool ¤t_map_lock, bool &show_map_properties_panel, bool &show_custom_bg_color_editor, bool &show_overlay_editor, bool &show_overlay_preview, int &game_state, EditingMode ¤t_mode, EntityEditMode &entity_edit_mode)
zelda3::Overworld * overworld_
void ForceRefreshGraphics(int map_index)
void RefreshSiblingMapGraphics(int map_index, bool include_self=false)
void DrawTileGraphicsTab(int current_map)
ForceRefreshGraphicsCallback force_refresh_graphics_
void DrawQuickAccessPopup()
std::string GetOverlayDescription(uint16_t overlay_id)
void DrawOverlayControls(int current_map, bool &show_overlay_preview)
absl::Status RefreshMapPalette()
void DrawGraphicsPopup(int current_map, int game_state)
RAII timer for automatic timing management.
constexpr uint16_t snes() const
Get SNES 15-bit color.
Modern, robust canvas for drawing and manipulating graphics.
void set_scrolling(ImVec2 scroll)
auto global_scale() const
void SetUsageMode(CanvasUsage usage)
void ClearContextMenuItems()
void AddContextMenuItem(const gui::CanvasMenuItem &item)
void set_global_scale(float scale)
static float GetButtonPadding()
static float GetStandardSpacing()
static bool SupportsCustomBGColors(OverworldVersion version)
Check if ROM supports custom background colors per area (v2+)
static OverworldVersion GetVersion(const Rom &rom)
Detect ROM version from ASM marker byte.
static bool SupportsAreaEnum(OverworldVersion version)
Check if ROM supports area enum system (v3+ only)
static bool SupportsAnimatedGFX(OverworldVersion version)
Check if ROM supports animated GFX selection (v3+)
static bool SupportsExpandedSpace(OverworldVersion version)
Check if ROM uses expanded ROM space for overworld data.
static const char * GetVersionName(OverworldVersion version)
Get human-readable version name for display/logging.
auto overworld_map(int i) const
auto mutable_overworld_map(int i)
absl::Status ConfigureMultiAreaMap(int parent_index, AreaSizeEnum size)
Configure a multi-area map structure (Large/Wide/Tall)
struct snes_color snes_color
SNES color in 15-bit RGB format (BGR555)
#define ICON_MD_GRID_VIEW
#define ICON_MD_LOCK_OPEN
#define ICON_MD_LIGHTBULB
#define ICON_MD_PHOTO_SIZE_SELECT_LARGE
#define ICON_MD_OFFLINE_BOLT
#define ICON_MD_PLAY_ARROW
#define ICON_MD_OPEN_IN_FULL
#define ICON_MD_VISIBILITY
#define ICON_MD_FORMAT_COLOR_FILL
#define ICON_MD_DOOR_BACK
#define ICON_MD_AUTO_FIX_HIGH
#define ICON_MD_MUSIC_NOTE
#define ICON_MD_ASPECT_RATIO
#define ICON_MD_ANIMATION
#define ICON_MD_DOOR_FRONT
#define ICON_MD_HELP_OUTLINE
#define ICON_MD_ADD_LOCATION
#define ICON_MD_EDIT_NOTE
#define ICON_MD_OPEN_IN_NEW
#define ICON_MD_PEST_CONTROL_RODENT
#define ICON_MD_CONTENT_COPY
#define ICON_MD_COLOR_LENS
#define HOVER_HINT(string)
constexpr const char * kAreaSizeNames[]
constexpr unsigned int kOverworldMapSize
constexpr float kOverworldMaxZoom
constexpr float kTableColumnWorld
constexpr float kOverworldMinZoom
constexpr const char * kWorldNames[]
constexpr float kHexByteInputWidth
constexpr float kComboWorldWidth
constexpr float kTableColumnMap
constexpr float kTableColumnAreaSize
constexpr float kOverworldZoomStep
constexpr float kComboGameStateWidth
constexpr float kInputFieldSize
constexpr const char * kGameStateNames[]
constexpr float kIconButtonWidth
constexpr float kHexWordInputWidth
constexpr float kComboAreaSizeWidth
constexpr float kTableColumnLock
constexpr const char * kOverworld
bool InputHexWord(const char *label, uint16_t *data, float input_width, bool no_step)
bool ToggleButton(const char *label, bool active, const ImVec2 &size)
ImVec4 ConvertSnesColorToImVec4(const gfx::SnesColor &color)
Convert SnesColor to standard ImVec4 for display.
bool InputHexWordCustom(const char *label, uint16_t *data, float input_width)
std::string MakePopupId(size_t session_id, const std::string &editor_name, const std::string &popup_name)
Generate session-aware popup IDs to prevent conflicts in multi-editor layouts.
gfx::SnesColor ConvertImVec4ToSnesColor(const ImVec4 &color)
Convert standard ImVec4 to SnesColor.
bool InputHexByte(const char *label, uint8_t *data, float input_width, bool no_step)
constexpr int OverworldCustomAreaSpecificBGEnabled
constexpr int kNumOverworldMaps
constexpr int kOverworldMusicBeginning
AreaSizeEnum
Area size enumeration for v3+ ROMs.
constexpr int OverworldCustomASMHasBeenApplied
constexpr int kOverworldMusicAgahnim
@ kVanilla
0xFF in ROM, no ZScream ASM applied
constexpr int kOverworldMusicMasterSword
constexpr int kOverworldMusicZelda
constexpr int OverworldCustomSubscreenOverlayEnabled
constexpr int OverworldCustomAreaSpecificBGPalette
constexpr int OverworldCustomSubscreenOverlayArray
SNES color in 15-bit RGB format (BGR555)