10#include "absl/strings/str_format.h"
23#include "imgui/imgui.h"
37 {.card_id =
"screen.dungeon_maps",
38 .display_name =
"Dungeon Maps",
39 .window_title =
" Dungeon Map Editor",
42 .shortcut_hint =
"Alt+1",
44 .enabled_condition = [
this]() {
return rom()->
is_loaded(); },
45 .disabled_tooltip =
"Load a ROM first"});
46 window_manager->RegisterPanel(
47 {.card_id =
"screen.inventory_menu",
48 .display_name =
"Inventory Menu",
49 .window_title =
" Inventory Menu",
52 .shortcut_hint =
"Alt+2",
54 .enabled_condition = [
this]() {
return rom()->
is_loaded(); },
55 .disabled_tooltip =
"Load a ROM first"});
56 window_manager->RegisterPanel(
57 {.card_id =
"screen.overworld_map",
58 .display_name =
"Overworld Map",
59 .window_title =
" Overworld Map",
62 .shortcut_hint =
"Alt+3",
64 .enabled_condition = [
this]() {
return rom()->
is_loaded(); },
65 .disabled_tooltip =
"Load a ROM first"});
66 window_manager->RegisterPanel(
67 {.card_id =
"screen.title_screen",
68 .display_name =
"Title Screen",
69 .window_title =
" Title Screen",
72 .shortcut_hint =
"Alt+4",
74 .enabled_condition = [
this]() {
return rom()->
is_loaded(); },
75 .disabled_tooltip =
"Load a ROM first"});
76 window_manager->RegisterPanel(
77 {.card_id =
"screen.naming_screen",
78 .display_name =
"Naming Screen",
79 .window_title =
" Naming Screen",
82 .shortcut_hint =
"Alt+5",
84 .enabled_condition = [
this]() {
return rom()->
is_loaded(); },
85 .disabled_tooltip =
"Load a ROM first"});
88 window_manager->RegisterWindowContent(std::make_unique<DungeonMapsPanel>(
90 window_manager->RegisterWindowContent(std::make_unique<InventoryMenuPanel>(
92 window_manager->RegisterWindowContent(
93 std::make_unique<OverworldMapScreenPanel>(
95 window_manager->RegisterWindowContent(std::make_unique<TitleScreenPanel>(
97 window_manager->RegisterWindowContent(std::make_unique<NamingScreenPanel>(
101 window_manager->OpenWindow(
"screen.title_screen");
108 return absl::FailedPreconditionError(
109 "Screen Editor requires a loaded ROM and GameData");
111 if (
game_data()->palette_groups.dungeon_main.size() <= 3) {
112 return absl::FailedPreconditionError(
113 "Screen Editor requires dungeon palette 3");
125 for (
int i = 0; i < 4; i++) {
128 sheet->Create(source.width(), source.height(), source.depth(),
130 sheet->metadata() = source.metadata();
132 *
game_data()->palette_groups.dungeon_main.mutable_palette(3));
140 const int tile8_width = 128;
141 const int tile8_height = 128;
142 std::vector<uint8_t> tile8_data(tile8_width * tile8_height);
145 for (
int sheet_idx = 0; sheet_idx < 4; sheet_idx++) {
146 const auto& sheet = *
sheets_[sheet_idx];
147 int dest_y_offset = sheet_idx * 32;
149 for (
int y = 0; y < 32; y++) {
150 for (
int x = 0; x < 128; x++) {
151 int src_index = y * 128 + x;
152 int dest_index = (dest_y_offset + y) * 128 + x;
154 if (src_index < sheet.size() && dest_index < tile8_data.size()) {
155 tile8_data[dest_index] = sheet.data()[src_index];
174 return absl::OkStatus();
179 return absl::FailedPreconditionError(
180 "Screen Editor ROM-backed state is invalid; reload Screen assets "
184 return absl::FailedPreconditionError(
185 "Screen Editor edits cannot all participate safely in the coordinated "
186 "ROM save; title-screen and pause-map ROM writes remain disabled until "
187 "write/reopen/readback verification exists, so discard the pending "
188 "edits before saving the ROM");
195 return absl::OkStatus();
213 tr(
"Screen assets are unavailable. Reload the active ROM before "
214 "drawing or editing the inventory screen."));
224 ImGui::TextColored(theme.text_error_red,
225 tr(
"Error loading inventory: %s"),
233 if (ImGui::BeginTable(
"InventoryScreen", 4, ImGuiTableFlags_Resizable)) {
234 ImGui::TableSetupColumn(
"Canvas");
235 ImGui::TableSetupColumn(
"Tilesheet");
236 ImGui::TableSetupColumn(
"Item Icons");
237 ImGui::TableSetupColumn(
"Palette");
238 ImGui::TableHeadersRow();
240 ImGui::TableNextColumn();
252 ImGui::TableNextColumn();
255 frame_opts.
canvas_size = ImVec2(128 * 2 + 2, (192 * 2) + 4);
265 ImGui::TableNextColumn();
268 ImGui::TableNextColumn();
284 if (ImGui::BeginTable(
"InventoryToolset", 8, ImGuiTableFlags_SizingFixedFit,
286 ImGui::TableSetupColumn(
"#drawTool");
287 ImGui::TableSetupColumn(
"#sep1");
288 ImGui::TableSetupColumn(
"#zoomOut");
289 ImGui::TableSetupColumn(
"#zoomIN");
290 ImGui::TableSetupColumn(
"#sep2");
291 ImGui::TableSetupColumn(
"#bg2Tool");
292 ImGui::TableSetupColumn(
"#bg3Tool");
293 ImGui::TableSetupColumn(
"#itemTool");
295 ImGui::TableNextColumn();
300 ImGui::EndDisabled();
301 ImGui::TableNextColumn();
306 ImGui::EndDisabled();
307 ImGui::TableNextColumn();
309 ImGui::TableNextColumn();
313 ImGui::TableNextColumn();
317 ImGui::TableNextColumn();
319 ImGui::TableNextColumn();
323 ImGui::TableNextColumn();
333 if (ImGui::BeginChild(
"##ItemIconsList", ImVec2(0, 0),
true,
334 ImGuiWindowFlags_HorizontalScrollbar)) {
335 ImGui::Text(tr(
"Item Icons (2x2 tiles each)"));
341 tr(
"No item icons loaded. Icons will be loaded when the "
342 "inventory is initialized."));
348 if (ImGui::BeginTable(
"##IconsTable", 2,
349 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
350 ImGui::TableSetupColumn(
"Icon Name");
351 ImGui::TableSetupColumn(
"Tile Data");
352 ImGui::TableHeadersRow();
354 for (
size_t i = 0; i < icons.size(); i++) {
355 const auto& icon = icons[i];
357 ImGui::TableNextRow();
358 ImGui::TableNextColumn();
361 if (ImGui::Selectable(icon.name.c_str(),
false,
362 ImGuiSelectableFlags_SpanAllColumns)) {
366 ImGui::TableNextColumn();
368 ImGui::Text(tr(
"TL:%04X TR:%04X"), icon.tile_tl, icon.tile_tr);
370 ImGui::Text(tr(
"BL:%04X BR:%04X"), icon.tile_bl, icon.tile_br);
377 ImGui::TextWrapped(tr(
378 "NOTE: Individual icon editing will be implemented in the future "
379 "Oracle of Secrets menu editor. Each icon is composed of 4 tile words "
380 "representing a 2x2 arrangement of 8x8 tiles in SNES tile format "
381 "(vhopppcc cccccccc)."));
390 ImGui::TextWrapped(tr(
"No valid dungeon-map floor is loaded."));
404 auto boss_room = current_dungeon.boss_room;
407 std::vector<int> tile_ids_to_render;
408 std::vector<ImVec2> tile_positions;
413 if (current_dungeon.floor_rooms[
floor_number][j] != 0x0F) {
414 int tile16_id = current_dungeon.floor_gfx[
floor_number][j];
415 int posX = ((j % 5) * 32);
416 int posY = ((j / 5) * 32);
419 tile_ids_to_render.push_back(tile16_id);
420 tile_positions.emplace_back(posX * 2, posY * 2);
425 for (
size_t idx = 0; idx < tile_ids_to_render.size(); ++idx) {
426 int tile16_id = tile_ids_to_render[idx];
427 ImVec2 pos = tile_positions[idx];
432 if (tiles_per_row <= 0 || tiles_per_column <= 0 || tile16_id < 0 ||
433 tile16_id >= tiles_per_row * tiles_per_column) {
436 const int tile_x = (tile16_id % tiles_per_row) * 16;
437 const int tile_y = (tile16_id / tiles_per_row) * 16;
439 std::vector<uint8_t> tile_data(16 * 16);
440 int tile_data_offset = 0;
457 if (cached_tile && cached_tile->is_active()) {
459 if (!cached_tile->texture()) {
470 if (current_dungeon.floor_rooms[
floor_number][j] != 0x0F) {
471 int posX = ((j % 5) * 32);
472 int posY = ((j / 5) * 32);
474 if (current_dungeon.floor_rooms[
floor_number][j] == boss_room) {
494 const int room = x + (y * 5);
503 ImGui::TextWrapped(tr(
"No valid dungeon map is loaded."));
507 const int floor_count =
508 current_dungeon.nbr_of_floor + current_dungeon.nbr_of_basement;
509 if (floor_count <= 0 ||
510 floor_count >
static_cast<int>(current_dungeon.floor_rooms.size()) ||
511 floor_count >
static_cast<int>(current_dungeon.floor_gfx.size()) ||
514 ImGui::TextWrapped(tr(
"This dungeon has no drawable map floors."));
524 for (
int i = 0; i < floor_count; i++) {
525 int basement_num = current_dungeon.nbr_of_basement - i;
526 std::string tab_name = absl::StrFormat(
"Basement %d", basement_num);
527 if (i >= current_dungeon.nbr_of_basement) {
528 tab_name = absl::StrFormat(
"Floor %d",
529 i - current_dungeon.nbr_of_basement + 1);
531 if (ImGui::BeginTabItem(tab_name.data())) {
548 "Edit room assignment"));
565 const auto button_size = ImVec2(130, 0);
567 if (ImGui::Button(tr(
"Add Floor"), button_size) &&
568 current_dungeon.nbr_of_floor < 8) {
570 current_dungeon.nbr_of_floor++;
575 if (ImGui::Button(tr(
"Remove Floor"), button_size) &&
576 current_dungeon.nbr_of_floor > 0) {
578 current_dungeon.nbr_of_floor--;
583 if (ImGui::Button(tr(
"Add Basement"), button_size) &&
584 current_dungeon.nbr_of_basement < 8) {
586 current_dungeon.nbr_of_basement++;
591 if (ImGui::Button(tr(
"Remove Basement"), button_size) &&
592 current_dungeon.nbr_of_basement > 0) {
594 current_dungeon.nbr_of_basement--;
599 if (ImGui::Button(tr(
"Copy Floor"), button_size)) {
603 if (ImGui::Button(tr(
"Paste Floor"), button_size)) {
634 ImGui::TextWrapped(tr(
"Dungeon-map graphics are not ready to draw."));
638 if (ImGui::BeginChild(
"##DungeonMapTiles", ImVec2(0, 0),
true)) {
642 tilesheet_opts.
canvas_size = ImVec2((256 * 2) + 2, (192 * 2) + 4);
658 ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
660 const int selected_tile16 =
static_cast<int>(
664 if (selected_tile16 >= 0 &&
701 auto current_tile_rt =
710 const int tiles_per_row =
716 std::vector<uint8_t> tile_data(64);
717 for (
int py = 0; py < 8; py++) {
718 for (
int px = 0; px < 8; px++) {
719 int src_x = tile_x + px;
720 int src_y = tile_y + py;
722 int dst_index = py * 8 + px;
733 std::move(new_tile8));
737 if (cached_tile8 && cached_tile8->is_active()) {
739 if (!cached_tile8->texture()) {
761 auto* selected_tile =
763 if (selected_tile && selected_tile->is_active()) {
765 if (!selected_tile->texture()) {
817 tr(
"Screen assets are unavailable. Reload the active ROM before "
818 "drawing or editing dungeon maps."));
822 ImGui::TextWrapped(tr(
"No valid dungeon-map model is loaded."));
835 ImGui::BeginDisabled();
837 ImGui::EndDisabled();
838 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
840 tr(
"Dungeon-map Tile16 saving is disabled until it can participate in "
841 "the coordinated ROM save transaction."));
844 static std::vector<std::string> dungeon_names = {
845 "Sewers/Sanctuary",
"Hyrule Castle",
"Eastern Palace",
846 "Desert Palace",
"Tower of Hera",
"Agahnim's Tower",
847 "Palace of Darkness",
"Swamp Palace",
"Skull Woods",
848 "Thieves' Town",
"Ice Palace",
"Misery Mire",
849 "Turtle Rock",
"Ganon's Tower"};
851 if (ImGui::BeginTable(
"DungeonMapsTable", 4,
852 ImGuiTableFlags_Resizable |
853 ImGuiTableFlags_Reorderable |
854 ImGuiTableFlags_Hideable)) {
855 ImGui::TableSetupColumn(
"Dungeon");
856 ImGui::TableSetupColumn(
"Map");
857 ImGui::TableSetupColumn(
"Rooms Gfx");
858 ImGui::TableSetupColumn(
"Tiles Gfx");
859 ImGui::TableHeadersRow();
861 ImGui::TableNextColumn();
862 const size_t dungeon_count =
864 for (
size_t i = 0; i < dungeon_count; i++) {
867 absl::StrFormat(
"%d", i), dungeon_names[i]);
868 if (ImGui::IsItemClicked()) {
873 ImGui::TableNextColumn();
876 ImGui::TableNextColumn();
879 ImGui::TableNextColumn();
893 ImGui::Text(tr(
"For use with custom inserted graphics assembly patches."));
894 if (ImGui::Button(tr(
"Load GFX from BIN file")))
903 if (!bin_file.empty()) {
904 std::ifstream file(bin_file, std::ios::binary);
905 if (file.is_open()) {
907 std::vector<uint8_t> bin_data((std::istreambuf_iterator<char>(file)),
908 std::istreambuf_iterator<char>());
913 std::vector<std::vector<uint8_t>> gfx_sheets;
914 for (
int i = 0; i < 4; i++) {
915 gfx_sheets.emplace_back(converted_bin.begin() + (i * 0x1000),
916 converted_bin.begin() + ((i + 1) * 0x1000));
918 sheet->Create(128, 32, 8, gfx_sheets[i]);
920 *
game_data()->palette_groups.dungeon_main.mutable_palette(3));
929 status_ = absl::InternalError(
"Failed to load dungeon map tile16");
939 tr(
"Screen assets are unavailable. Reload the active ROM before "
940 "drawing or editing the title screen."));
948 ImGui::TextColored(theme.text_error_red,
949 tr(
"Error loading title screen: %s"),
957 ImGui::Text(tr(
"Title screen not loaded. Ensure ROM is loaded."));
966 ImGui::BeginDisabled();
970 ImGui::EndDisabled();
971 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
973 tr(
"Title-screen ROM saving is disabled until write/reopen/readback "
974 "verification exists."));
998 if (ImGui::BeginTable(
"TitleScreenTable", 2,
999 ImGuiTableFlags_Resizable | ImGuiTableFlags_Borders)) {
1000 ImGui::TableSetupColumn(
"Title Screen (Composite)");
1001 ImGui::TableSetupColumn(
"Tile Selector");
1002 ImGui::TableHeadersRow();
1005 ImGui::TableNextColumn();
1009 ImGui::TableNextColumn();
1034 if (composite_bitmap.is_active()) {
1043 int tile_x =
static_cast<int>(click_pos.x) / 8;
1044 int tile_y =
static_cast<int>(click_pos.y) / 8;
1046 if (tile_x >= 0 && tile_x < 32 && tile_y >= 0 && tile_y < 32) {
1047 int tilemap_index = tile_y * 32 + tile_x;
1053 tile_word |= 0x4000;
1055 tile_word |= 0x8000;
1090 if (bg1_bitmap.is_active()) {
1099 int tile_x =
static_cast<int>(click_pos.x) / 8;
1100 int tile_y =
static_cast<int>(click_pos.y) / 8;
1102 if (tile_x >= 0 && tile_x < 32 && tile_y >= 0 && tile_y < 32) {
1103 int tilemap_index = tile_y * 32 + tile_x;
1109 tile_word |= 0x4000;
1111 tile_word |= 0x8000;
1137 if (bg2_bitmap.is_active()) {
1146 int tile_x =
static_cast<int>(click_pos.x) / 8;
1147 int tile_y =
static_cast<int>(click_pos.y) / 8;
1149 if (tile_x >= 0 && tile_x < 32 && tile_y >= 0 && tile_y < 32) {
1150 int tilemap_index = tile_y * 32 + tile_x;
1156 tile_word |= 0x4000;
1158 tile_word |= 0x8000;
1184 if (tiles8_bitmap.is_active()) {
1193 int tile_x =
static_cast<int>(click_pos.x) / 8;
1194 int tile_y =
static_cast<int>(click_pos.y) / 8;
1195 int tiles_per_row = 128 / 8;
1213 ImGui::SetNextItemWidth(100);
1223 tr(
"Screen assets are unavailable. Reload the active ROM before "
1224 "drawing or editing the pause-map screen."));
1232 ImGui::TextColored(theme.text_error_red,
1233 tr(
"Error loading overworld map: %s"),
1241 ImGui::Text(tr(
"Overworld map not loaded. Ensure ROM is loaded."));
1248 if (ImGui::Button(tr(
"Paint Mode"))) {
1251 if (ImGui::IsItemHovered()) {
1252 ImGui::SetTooltip(tr(
1253 "Paint the pause-menu world map: choose an 8x8 tile in Tileset, then "
1254 "click Map Canvas."));
1257 ImGui::BeginDisabled();
1258 if (ImGui::Button(tr(
"Save World Map"))) {
1261 ImGui::EndDisabled();
1262 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
1263 ImGui::SetTooltip(tr(
1264 "Pause-map ROM saving is disabled until Light World, Dark World, and "
1265 "palette writes pass write/reopen/readback verification."));
1282 if (ImGui::Button(tr(
"Load Custom Map..."))) {
1284 if (!path.empty()) {
1287 ImGui::OpenPopup(
"CustomMapLoadError");
1294 if (ImGui::Button(tr(
"Save Custom Map..."))) {
1296 if (!path.empty()) {
1299 ImGui::OpenPopup(
"CustomMapSaveSuccess");
1307 ImGui::TextWrapped(tr(
1308 "This edits the pause-menu world map art, not the 160 playable "
1309 "overworld areas. For area-map painting, entrances, exits, items, and "
1310 "sprites, use Overworld Editor. Paint flow here: pick an 8x8 tile from "
1311 "Tileset, then click Map Canvas; use Light/Dark World to choose the "
1316 if (ImGui::BeginPopup(
"CustomMapLoadError")) {
1317 ImGui::Text(tr(
"Error loading custom map: %s"),
status_.message().data());
1320 if (ImGui::BeginPopup(
"CustomMapSaveSuccess")) {
1321 ImGui::Text(tr(
"Custom map saved successfully!"));
1326 if (ImGui::BeginTable(
"OWMapTable", 3,
1327 ImGuiTableFlags_Resizable | ImGuiTableFlags_Borders)) {
1328 ImGui::TableSetupColumn(
"Map Canvas");
1329 ImGui::TableSetupColumn(
"Tileset");
1330 ImGui::TableSetupColumn(
"Palette");
1331 ImGui::TableHeadersRow();
1334 ImGui::TableNextColumn();
1340 if (map_bitmap.is_active()) {
1349 int tile_x =
static_cast<int>(click_pos.x) / 8;
1350 int tile_y =
static_cast<int>(click_pos.y) / 8;
1352 if (tile_x >= 0 && tile_x < 64 && tile_y >= 0 && tile_y < 64) {
1353 int tile_index = tile_x + (tile_y * 64);
1378 ImGui::TableNextColumn();
1384 if (tiles8_bitmap.is_active()) {
1392 int tile_x =
static_cast<int>(click_pos.x) / 8;
1393 int tile_y =
static_cast<int>(click_pos.y) / 8;
1402 ImGui::TableNextColumn();
1406 const auto palette_before = palette;
1408 if (palette != palette_before) {
1417 static bool show_bg1 =
true;
1418 static bool show_bg2 =
true;
1419 static bool show_bg3 =
true;
1421 static bool drawing_bg1 =
true;
1422 static bool drawing_bg2 =
false;
1423 static bool drawing_bg3 =
false;
1425 ImGui::Checkbox(tr(
"Show BG1"), &show_bg1);
1427 ImGui::Checkbox(tr(
"Show BG2"), &show_bg2);
1429 ImGui::Checkbox(tr(
"Draw BG1"), &drawing_bg1);
1431 ImGui::Checkbox(tr(
"Draw BG2"), &drawing_bg2);
1433 ImGui::Checkbox(tr(
"Draw BG3"), &drawing_bg3);
1502 if (idx >= 0 && idx <
static_cast<int>(
dungeon_maps_.size())) {
1528 return absl::FailedPreconditionError(
1529 "Title-screen ROM saving is disabled until write/reopen/readback "
1530 "verification exists");
1534 return absl::FailedPreconditionError(
1535 "Pause-map ROM saving is disabled until Light World, Dark World, and "
1536 "palette writes pass write/reopen/readback verification");
1550 sheet = std::make_unique<gfx::Bitmap>();
1573 selected_dungeon < static_cast<int>(
dungeon_maps_.size()) &&
1582 return floor < static_cast<int>(dungeon.floor_rooms.size()) &&
1583 floor < static_cast<int>(dungeon.floor_gfx.size()) &&
1642 canvas->ClearSelection();
project::ResourceLabelManager * resource_label()
UndoManager undo_manager_
zelda3::GameData * game_data() const
EditorDependencies dependencies_
void DrawTitleScreenEditor()
void DrawDungeonMapsRoomGfx()
Draw dungeon room graphics editor with enhanced tile16 editing.
absl::Status RefreshRomBackedState()
gfx::SnesPalette palette_
absl::Status Undo() override
void DrawTitleScreenBlocksetSelector()
void MarkOverworldMapModified()
bool title_screen_loaded_
ScreenSnapshot CaptureTile16CompSnapshot() const
gui::Canvas ow_map_canvas_
absl::Status SaveOverworldMapToRom()
gfx::Bitmap * GetOrCreateSheet(int index)
gfx::Tilemap tile16_blockset_
ScreenSnapshot pending_dungeon_before_
bool pending_overworld_map_palette_changes_
void DrawTitleScreenBG2Canvas()
bool pending_dungeon_map_tile16_changes_
gui::Canvas tilemap_canvas_
void DrawInventoryItemIcons()
std::array< gfx::TileInfo, 4 > current_tile16_info
absl::Status Save() override
absl::Status Load() override
void SaveDungeonMapUndoState(const std::string &description)
void InvalidateRomBackedState()
bool pending_dungeon_map_changes_
absl::Status Update() override
gui::Canvas screen_canvas_
std::string pending_tile16_desc_
void DrawTitleScreenBG1Canvas()
bool HasValidDungeonFloorSelection(int floor) const
gui::Canvas title_bg1_canvas_
void RestoreFromSnapshot(const ScreenSnapshot &snapshot)
zelda3::OverworldMapScreen ow_map_screen_
void MarkTitleScreenModified()
ScreenSnapshot pending_tile16_before_
void Initialize() override
bool HasValidDungeonSelection() const
int selected_title_tile16_
ScreenSnapshot CaptureDungeonMapSnapshot() const
bool pending_title_screen_changes_
gui::Canvas current_tile_canvas_
void DrawDungeonMapsEditor()
Draw dungeon maps editor with enhanced ROM hacking features.
gui::Canvas title_bg2_canvas_
absl::Status Redo() override
void SaveTile16CompUndoState(const std::string &description)
void DrawInventoryToolset()
void MarkOverworldMapPaletteModified()
void CommitTile16CompUndo()
gfx::Tilemap tile8_tilemap_
bool has_pending_dungeon_undo_
void DrawTitleScreenCompositeCanvas()
absl::Status SaveTitleScreenToRom()
void ResetRomBackedStateForLoad()
zelda3::TitleScreen title_screen_
void DrawOverworldMapEditor()
EditingMode current_mode_
std::unique_ptr< zelda3::Inventory > inventory_
zelda3::DungeonMapLabels dungeon_map_labels_
bool paste_button_pressed
gui::Canvas ow_tileset_canvas_
gui::Canvas title_blockset_canvas_
bool rom_backed_state_valid_
bool HasPendingScreenChanges() const
void DrawDungeonMapToolset()
gui::Canvas tilesheet_canvas_
void DrawNamingScreenEditor()
void MarkDungeonMapModified()
void DrawDungeonMapScreen(int i)
bool has_pending_tile16_undo_
void DrawDungeonMapsTabs()
void RefreshTileCacheForReload(gfx::Tilemap &tilemap)
std::vector< zelda3::DungeonMap > dungeon_maps_
std::string pending_dungeon_desc_
void CommitDungeonMapUndo()
void DrawInventoryMenuEditor()
bool pending_overworld_map_changes_
void MarkDungeonMapTile16Modified()
void Push(std::unique_ptr< UndoAction > action)
void RegisterPanel(size_t session_id, const WindowDescriptor &base_info)
void QueueTextureCommand(TextureCommandType type, Bitmap *bitmap)
std::array< gfx::Bitmap, 223 > & gfx_sheets()
Get reference to all graphics sheets.
Represents a bitmap image optimized for SNES ROM hacking.
const uint8_t * data() const
const SnesPalette & palette() const
void Create(int width, int height, int depth, std::span< uint8_t > data)
Create a bitmap with the given dimensions and data.
void set_data(const std::vector< uint8_t > &data)
void SetPalette(const SnesPalette &palette)
Set the palette for the bitmap using SNES palette format.
void Get16x16Tile(int tile_x, int tile_y, std::vector< uint8_t > &tile_data, int &tile_data_offset)
Extract a 16x16 tile from the bitmap (SNES metatile size)
RAII timer for automatic timing management.
void DrawBitmap(Bitmap &bitmap, int border_offset, float scale)
void DrawOutlineWithColor(int x, int y, int w, int h, ImVec4 color)
ImVector< ImVec2 > * mutable_points()
int GetTileIdFromMousePos()
bool DrawTileSelector(int size, int size_y=0)
bool DrawTilePainter(const Bitmap &bitmap, int size, float scale=1.0f)
CanvasConfig & GetConfig()
bool IsMouseHovering() const
void DrawBitmapTable(const BitmapTable &gfx_bin)
void DrawBackground(ImVec2 canvas_size=ImVec2(0, 0))
const ImVector< ImVec2 > & points() const
void DrawGrid(float grid_step=64.0f, int tile_id_offset=8)
void DrawText(const std::string &text, int x, int y)
static std::string ShowSaveFileDialog(const std::string &default_name="", const std::string &default_extension="")
ShowSaveFileDialog opens a save file dialog and returns the selected filepath. Uses global feature fl...
static std::string ShowOpenFileDialog()
ShowOpenFileDialog opens a file dialog and returns the selected filepath. Uses global feature flag to...
auto & mutable_lw_tiles()
absl::Status SaveCustomMap(const std::string &file_path, bool use_dark_world)
Save map data to external binary file.
auto & mutable_dw_tiles()
absl::Status LoadCustomMap(const std::string &file_path)
Load custom map from external binary file.
absl::Status RenderMapLayer(bool use_dark_world)
Render map tiles into bitmap.
absl::Status Create(Rom *rom)
Initialize and load overworld map data from ROM.
auto & composite_bitmap()
auto & mutable_bg1_buffer()
absl::Status Create(Rom *rom, GameData *game_data=nullptr)
Initialize and load title screen data from ROM.
auto & mutable_bg2_buffer()
absl::Status RenderCompositeLayer(bool show_bg1, bool show_bg2)
Render composite layer with BG1 on top of BG2 with transparency.
absl::Status RenderBG2Layer()
Render BG2 tilemap into bitmap pixels Converts tile IDs from tiles_bg2_buffer_ into pixel data.
absl::Status RenderBG1Layer()
Render BG1 tilemap into bitmap pixels Converts tile IDs from tiles_bg1_buffer_ into pixel data.
#define ICON_MD_MORE_VERT
#define ICON_MD_INVENTORY
#define ASSIGN_OR_RETURN(type_variable_name, expression)
const AgentUITheme & GetTheme()
void EnsureCompositeBitmapTextureQueued(gfx::Bitmap &composite)
void RenderTile16(IRenderer *renderer, Tilemap &tilemap, int tile_id)
void ModifyTile16(Tilemap &tilemap, const std::vector< uint8_t > &data, const TileInfo &top_left, const TileInfo &top_right, const TileInfo &bottom_left, const TileInfo &bottom_right, int sheet_offset, int tile_id)
void UpdateTile16(IRenderer *renderer, Tilemap &tilemap, int tile_id)
std::vector< uint8_t > GetTilemapData(Tilemap &tilemap, int tile_id)
std::vector< uint8_t > SnesTo8bppSheet(std::span< const uint8_t > sheet, int bpp, int num_sheets)
void EndCanvas(Canvas &canvas)
bool InputHexWord(const char *label, uint16_t *data, float input_width, bool no_step)
bool DrawTileSelector(const CanvasRuntime &rt, int size, int size_y, ImVec2 *out_selected_pos)
void BeginCanvas(Canvas &canvas, ImVec2 child_size)
void DrawBitmap(const CanvasRuntime &rt, gfx::Bitmap &bitmap, int border_offset=2, float scale=1.0f)
bool BeginThemedTabBar(const char *id, ImGuiTabBarFlags flags)
A stylized tab bar with "Mission Control" branding.
IMGUI_API absl::Status InlinePaletteEditor(gfx::SnesPalette &palette, const std::string &title, ImGuiColorEditFlags flags)
Full inline palette editor with color picker and copy options.
bool InputTileInfo(const char *label, gfx::TileInfo *tile_info)
IMGUI_API bool DisplayPalette(gfx::SnesPalette &palette, bool loaded)
bool ToolbarIconButton(const char *icon, const char *tooltip, bool is_active)
Convenience wrapper for toolbar-sized icon buttons.
bool InputHexByte(const char *label, uint8_t *data, float input_width, bool no_step)
std::string HexByte(uint8_t byte, HexStringParams params)
absl::Status LoadDungeonMapTile16(gfx::Tilemap &tile16_blockset, Rom &rom, GameData *game_data, const std::vector< uint8_t > &gfx_data, bool bin_mode)
Load the dungeon map tile16 from the ROM.
absl::StatusOr< std::vector< DungeonMap > > LoadDungeonMaps(Rom &rom, DungeonMapLabels &dungeon_map_labels)
Load the dungeon maps from the ROM.
absl::Status SaveDungeonMaps(Rom &rom, std::vector< DungeonMap > &dungeon_maps)
Save the dungeon maps to the ROM.
#define RETURN_IF_ERROR(expr)
zelda3::DungeonMap map_data
std::vector< std::array< std::string, zelda3::kNumRooms > > labels
WorkspaceWindowManager * window_manager
Unified screen editor snapshot.
DungeonMapSnapshot dungeon_map
Tile16CompSnapshot tile16_comp
std::array< gfx::TileInfo, 4 > tile_info
int y
Y coordinate or height.
int x
X coordinate or width.
PaletteGroup dungeon_main
auto mutable_palette(int i)
std::unordered_map< int, std::unique_ptr< Bitmap > > cache_
void CacheTile(int tile_id, const Bitmap &bitmap)
Cache a tile bitmap by copying it.
Bitmap * GetTile(int tile_id)
Get a cached tile by ID.
Tilemap structure for SNES tile-based graphics management.
Pair tile_size
Size of individual tiles (8x8 or 16x16)
TileCache tile_cache
Smart tile cache with LRU eviction.
Pair map_size
Size of tilemap in tiles.
Bitmap atlas
Master bitmap containing all tiles.
std::vector< std::array< gfx::TileInfo, 4 > > tile_info
Tile metadata (4 tiles per 16x16)
std::optional< float > grid_step
void SelectableLabelWithNameEdit(bool selected, const std::string &type, const std::string &key, const std::string &defaultValue)
gfx::PaletteGroupMap palette_groups