diff --git a/src/app/editor/editor_manager.cc b/src/app/editor/editor_manager.cc index a7af527b..d737d4a4 100644 --- a/src/app/editor/editor_manager.cc +++ b/src/app/editor/editor_manager.cc @@ -58,10 +58,8 @@ void EditorManager::Initialize(std::string filename) { absl::Status EditorManager::Update() { ManageKeyboardShortcuts(); - DrawYazeMenu(); - DrawStatusPopup(); - DrawAboutPopup(); - DrawInfoPopup(); + DrawMenuBar(); + DrawPopups(); if (rom()->is_loaded() && !rom_assets_loaded_) { auto& sheet_manager = GraphicsSheetManager::GetInstance(); @@ -71,8 +69,11 @@ absl::Status EditorManager::Update() { rom_assets_loaded_ = true; } - ManageActiveEditors(); - + if (!current_rom_) { + DrawHomepage(); + } else { + ManageActiveEditors(); + } return absl::OkStatus(); } @@ -298,7 +299,7 @@ void EditorManager::ManageKeyboardShortcuts() { } } -void EditorManager::DrawStatusPopup() { +void EditorManager::DrawPopups() { static absl::Status prev_status; if (!status_.ok()) { show_status_ = true; @@ -324,9 +325,7 @@ void EditorManager::DrawStatusPopup() { } End(); } -} -void EditorManager::DrawAboutPopup() { if (about_) OpenPopup("About"); if (BeginPopupModal("About", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { Text("Yet Another Zelda3 Editor - v%s", version_.c_str()); @@ -341,9 +340,7 @@ void EditorManager::DrawAboutPopup() { } EndPopup(); } -} -void EditorManager::DrawInfoPopup() { if (rom_info_) OpenPopup("ROM Information"); if (BeginPopupModal("ROM Information", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { @@ -359,11 +356,29 @@ void EditorManager::DrawInfoPopup() { } } -void EditorManager::DrawYazeMenu() { +void EditorManager::DrawHomepage() { + TextWrapped("Welcome to the Yet Another Zelda3 Editor (yaze)!"); + TextWrapped("This editor is designed to be a comprehensive tool for editing the Legend of Zelda: A Link to the Past."); + TextWrapped("The editor is still in development, so please report any bugs or issues you encounter."); + + static bool managed_startup = false; + + if (Button("Open ROM", ImVec2(200, 0))) { + LoadRom(); + } + SameLine(); + ImGui::Checkbox("Manage Startup", &managed_startup); + Separator(); + + settings_editor_.Update(); +} + +void EditorManager::DrawMenuBar() { static bool show_display_settings = false; if (BeginMenuBar()) { - DrawYazeMenuBar(); + DrawMenuContent(); + SameLine(GetWindowWidth() - GetStyle().ItemSpacing.x - CalcTextSize(ICON_MD_DISPLAY_SETTINGS).x - 110); PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); @@ -382,7 +397,7 @@ void EditorManager::DrawYazeMenu() { } } -void EditorManager::DrawYazeMenuBar() { +void EditorManager::DrawMenuContent() { static bool save_as_menu = false; static bool new_project_menu = false; @@ -447,11 +462,23 @@ void EditorManager::DrawYazeMenuBar() { MenuItem("Backup ROM", "", &backup_rom_); MenuItem("Save New Auto", "", &save_new_auto_); Separator(); - if (BeginMenu("Experiment Flags")) { - static FlagsMenu flags_menu; - flags_menu.Draw(); + static FlagsMenu flags_menu; + if (BeginMenu("System Flags")) { + flags_menu.DrawSystemFlags(); EndMenu(); } + if (BeginMenu("Overworld Flags")) { + flags_menu.DrawOverworldFlags(); + EndMenu(); + } + if (BeginMenu("Dungeon Flags")) { + flags_menu.DrawDungeonFlags(); + EndMenu(); + } + if (BeginMenu("Resource Flags")) { + flags_menu.DrawResourceFlags(); + EndMenu(); + } EndMenu(); } @@ -673,10 +700,25 @@ void EditorManager::DrawYazeMenuBar() { } } +void EditorManager::DrawRomMenu() { + if (roms_.empty()) return; + + // Dropdown in the center of the menu bar with ROMs + if (BeginMenu("ROM")) { + for (size_t i = 0; i < roms_.size(); ++i) { + if (MenuItem(roms_[i]->title().c_str())) { + current_rom_ = roms_[i].get(); + } + } + EndMenu(); + } +} + void EditorManager::LoadRom() { auto file_name = FileDialogWrapper::ShowOpenFileDialog(); auto load_rom = rom()->LoadFromFile(file_name); if (load_rom.ok()) { + current_rom_ = rom(); static RecentFilesManager manager("recent_files.txt"); manager.Load(); manager.AddFile(file_name); @@ -708,11 +750,13 @@ void EditorManager::OpenRomOrProject(const std::string &filename) { } } else { status_ = rom()->LoadFromFile(filename); + current_rom_ = rom(); } } absl::Status EditorManager::OpenProject() { RETURN_IF_ERROR(rom()->LoadFromFile(current_project_.rom_filename_)); + current_rom_ = rom(); if (!rom()->resource_label()->LoadLabels(current_project_.labels_filename_)) { return absl::InternalError( diff --git a/src/app/editor/editor_manager.h b/src/app/editor/editor_manager.h index 04846fe6..e5000869 100644 --- a/src/app/editor/editor_manager.h +++ b/src/app/editor/editor_manager.h @@ -46,6 +46,7 @@ class EditorManager : public SharedRom { active_editors_.push_back(&sprite_editor_); active_editors_.push_back(&message_editor_); active_editors_.push_back(&screen_editor_); + active_editors_.push_back(&settings_editor_); std::stringstream ss; ss << YAZE_VERSION_MAJOR << "." << YAZE_VERSION_MINOR << "." << YAZE_VERSION_PATCH; @@ -56,18 +57,18 @@ class EditorManager : public SharedRom { absl::Status Update(); auto emulator() -> emu::Emulator & { return emulator_; } - auto quit() { return quit_; } + auto quit() const { return quit_; } private: void ManageActiveEditors(); void ManageKeyboardShortcuts(); - void DrawStatusPopup(); - void DrawAboutPopup(); - void DrawInfoPopup(); + void DrawPopups(); + void DrawHomepage(); - void DrawYazeMenu(); - void DrawYazeMenuBar(); + void DrawMenuBar(); + void DrawMenuContent(); + void DrawRomMenu(); void LoadRom(); void SaveRom(); @@ -88,6 +89,8 @@ class EditorManager : public SharedRom { absl::Status status_; emu::Emulator emulator_; std::vector active_editors_; + std::vector> roms_; + Rom* current_rom_ = nullptr; Project current_project_; EditorContext editor_context_; diff --git a/src/app/editor/overworld/overworld_editor.cc b/src/app/editor/overworld/overworld_editor.cc index 1069a8f4..fe745d3f 100644 --- a/src/app/editor/overworld/overworld_editor.cc +++ b/src/app/editor/overworld/overworld_editor.cc @@ -61,7 +61,7 @@ absl::Status OverworldEditor::Update() { status_ = absl::OkStatus(); if (rom_.is_loaded() && !all_gfx_loaded_) { RETURN_IF_ERROR(tile16_editor_.InitBlockset( - tile16_blockset_bmp_, current_gfx_bmp_, tile16_individual_, + tile16_blockset_bmp_, current_gfx_bmp_, *overworld_.mutable_all_tiles_types())); ASSIGN_OR_RETURN(entrance_tiletypes_, zelda3::LoadEntranceTileTypes(rom_)); all_gfx_loaded_ = true; @@ -417,7 +417,7 @@ void OverworldEditor::DrawOverworldEdits() { // Render the updated map bitmap. RenderUpdatedMapBitmap(mouse_position, - tile16_individual_data_[current_tile16_]); + tile16_individual_[current_tile16_].vector()); // Calculate the correct superX and superY values int superY = current_map_ / 8; @@ -1031,15 +1031,18 @@ absl::Status OverworldEditor::Save() { } absl::Status OverworldEditor::LoadGraphics() { + core::logf("Loading overworld."); // Load the Link to the Past overworld. RETURN_IF_ERROR(overworld_.Load(rom_)) palette_ = overworld_.current_area_palette(); + core::logf("Loading overworld graphics."); // Create the area graphics image RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap( 0x80, kOverworldMapSize, 0x40, overworld_.current_graphics(), current_gfx_bmp_, palette_)); + core::logf("Loading overworld tileset."); // Create the tile16 blockset image RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap( 0x80, 0x2000, 0x08, overworld_.tile16_blockset_data(), @@ -1048,31 +1051,29 @@ absl::Status OverworldEditor::LoadGraphics() { // Copy the tile16 data into individual tiles. auto tile16_data = overworld_.tile16_blockset_data(); - tile16_individual_.reserve(zelda3::kNumTile16Individual); + core::logf("Loading overworld tile16 graphics."); // Loop through the tiles and copy their pixel data into separate vectors for (uint i = 0; i < zelda3::kNumTile16Individual; i++) { - std::vector tile_data(kTile16Size * kTile16Size, 0x00); + tile16_individual_[i].Create(kTile16Size, kTile16Size, 0x08, kTile16Size * kTile16Size); // Copy the pixel data for the current tile into the vector for (int ty = 0; ty < kTile16Size; ty++) { for (int tx = 0; tx < kTile16Size; tx++) { int position = tx + (ty * kTile16Size); uint8_t value = - tile16_data[(i % 8 * kTile16Size) + (i / 8 * kTile16Size * 0x80) + - (ty * 0x80) + tx]; - tile_data[position] = value; + tile16_data[(i % 8 * kTile16Size) + (i / 8 * kTile16Size * 0x80) + + (ty * 0x80) + tx]; + tile16_individual_[i].mutable_data()[position] = value; } } - // Add the vector for the current tile to the vector of tile pixel data - tile16_individual_data_.push_back(tile_data); - tile16_individual_.emplace_back(); - RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap( - kTile16Size, kTile16Size, 0x80, tile16_individual_data_[i], - tile16_individual_[i], palette_)); + RETURN_IF_ERROR(tile16_individual_[i].ApplyPalette(palette_)); + Renderer::GetInstance().RenderBitmap(&tile16_individual_[i]); + } + core::logf("Loading overworld maps."); // Render the overworld maps loaded from the ROM. for (int i = 0; i < zelda3::kNumOverworldMaps; ++i) { overworld_.set_current_map(i); @@ -1154,6 +1155,7 @@ void OverworldEditor::RefreshOverworldMap() { std::async(std::launch::async, refresh_map_async, source_map_id)); for (auto &each : futures) { + each.wait(); each.get(); } int n = is_large ? 4 : 1; @@ -1221,12 +1223,12 @@ absl::Status OverworldEditor::RefreshTile16Blockset() { // Copy the tile16 data into individual tiles. const auto tile16_data = overworld_.tile16_blockset_data(); - std::vector> futures; // Loop through the tiles and copy their pixel data into separate vectors + std::vector> futures; for (uint i = 0; i < zelda3::kNumTile16Individual; i++) { futures.push_back(std::async( std::launch::async, - [&](int index) { + [&](int index) -> absl::Status { std::vector tile_data(16 * 16, 0x00); for (int ty = 0; ty < 16; ty++) { for (int tx = 0; tx < 16; tx++) { @@ -1238,17 +1240,19 @@ absl::Status OverworldEditor::RefreshTile16Blockset() { } } tile16_individual_[index].set_data(tile_data); + RETURN_IF_ERROR(tile16_individual_[index].ApplyPalette(palette_)); + return absl::OkStatus(); }, i)); } for (auto &future : futures) { - future.get(); + future.wait(); + RETURN_IF_ERROR(future.get()); } // Render the bitmaps of each tile. for (uint id = 0; id < zelda3::kNumTile16Individual; id++) { - RETURN_IF_ERROR(tile16_individual_[id].ApplyPalette(palette_)); Renderer::GetInstance().UpdateBitmap(&tile16_individual_[id]); } diff --git a/src/app/editor/overworld/overworld_editor.h b/src/app/editor/overworld/overworld_editor.h index f89c1477..c679b797 100644 --- a/src/app/editor/overworld/overworld_editor.h +++ b/src/app/editor/overworld/overworld_editor.h @@ -233,15 +233,14 @@ class OverworldEditor : public Editor, public gfx::GfxContext { bool is_dragging_entity_ = false; std::vector selected_tile_data_; - std::vector> tile16_individual_data_; - std::vector tile16_individual_; + std::array tile16_individual_; std::vector> tile8_individual_data_; std::vector tile8_individual_; Rom& rom_; - Tile16Editor tile16_editor_; + Tile16Editor tile16_editor_{ tile16_individual_ }; GfxGroupEditor gfx_group_editor_; PaletteEditor palette_editor_; @@ -256,7 +255,7 @@ class OverworldEditor : public Editor, public gfx::GfxContext { gfx::BitmapTable current_graphics_set_; gfx::BitmapTable sprite_previews_; - zelda3::Overworld overworld_; + zelda3::Overworld overworld_{rom_}; zelda3::OverworldBlockset refresh_blockset_; zelda3::Sprite current_sprite_; @@ -264,10 +263,10 @@ class OverworldEditor : public Editor, public gfx::GfxContext { zelda3::OverworldEntrance current_entrance_; zelda3::OverworldExit current_exit_; zelda3::OverworldItem current_item_; - zelda3::OverworldEntranceTileTypes entrance_tiletypes_; + zelda3::OverworldEntranceTileTypes entrance_tiletypes_ = {}; - zelda3::GameEntity* current_entity_; - zelda3::GameEntity* dragged_entity_; + zelda3::GameEntity* current_entity_ = nullptr; + zelda3::GameEntity* dragged_entity_ = nullptr; gui::Canvas ow_map_canvas_{"OwMap", kOverworldCanvasSize, gui::CanvasGridSize::k64x64}; diff --git a/src/app/gui/canvas.cc b/src/app/gui/canvas.cc index 78a8cb1e..f035aa70 100644 --- a/src/app/gui/canvas.cc +++ b/src/app/gui/canvas.cc @@ -533,7 +533,7 @@ void Canvas::DrawOutlineWithColor(int x, int y, int w, int h, uint32_t color) { } void Canvas::DrawBitmapGroup(std::vector &group, - std::vector &tile16_individual_, + std::array &tile16_individual_, int tile_size, float scale) { if (selected_points_.size() != 2) { // points_ should contain exactly two points diff --git a/src/app/gui/canvas.h b/src/app/gui/canvas.h index f2f2ef93..7b30daf2 100644 --- a/src/app/gui/canvas.h +++ b/src/app/gui/canvas.h @@ -111,7 +111,7 @@ public: void DrawBitmapTable(const BitmapTable &gfx_bin); void DrawBitmapGroup(std::vector &group, - std::vector &tile16_individual_, + std::array& tile16_individual_, int tile_size, float scale = 1.0f); void DrawOutline(int x, int y, int w, int h); @@ -219,8 +219,6 @@ private: uint64_t edit_palette_group_name_index_ = 0; uint64_t edit_palette_sub_index_ = 0; - - ImDrawList* draw_list_ = nullptr; ImVec2 scrolling_; diff --git a/src/app/zelda3/overworld/overworld.h b/src/app/zelda3/overworld/overworld.h index 82f617eb..6f73f8a3 100644 --- a/src/app/zelda3/overworld/overworld.h +++ b/src/app/zelda3/overworld/overworld.h @@ -109,6 +109,8 @@ constexpr int NumberOfMap32 = Map32PerScreen * kNumOverworldMaps; */ class Overworld : public SharedRom { public: + Overworld(Rom& rom) : rom_(rom) {} + absl::Status Load(Rom &rom); absl::Status LoadOverworldMaps(); void LoadTileTypes(); @@ -227,7 +229,7 @@ class Overworld : public SharedRom { int &ttpos); void DecompressAllMapTiles(); - Rom rom_; + Rom& rom_; bool is_loaded_ = false; bool expanded_tile16_ = false; @@ -251,7 +253,7 @@ class Overworld : public SharedRom { std::vector all_holes_; std::vector all_exits_; std::vector all_items_; - std::vector> all_sprites_; + std::array, 3> all_sprites_; std::vector deleted_entrances_; std::vector> map_data_p1 = std::vector>(kNumOverworldMaps);