From fdda77c172d2752ce9015796bee81060796ca4a9 Mon Sep 17 00:00:00 2001 From: scawful Date: Sun, 3 Aug 2025 17:52:02 -0400 Subject: [PATCH] Refactor ROM handling and remove SharedRom singleton for improved architecture - Eliminated the SharedRom class to enhance modularity and reduce global state management. - Updated various classes to directly manage ROM instances, improving clarity and encapsulation. - Added new functions for loading messages and colors from ROM, enhancing functionality. - Refactored Canvas and Editor classes to utilize direct ROM references, streamlining interactions. - Improved documentation and comments for better code understanding and maintainability. --- docs/infrastructure.md | 7 +- incl/yaze.h | 49 +++- incl/zelda.h | 15 +- src/app/core/platform/app_delegate.mm | 33 +-- src/app/editor/graphics/gfx_group_editor.h | 5 +- src/app/editor/overworld/overworld_editor.cc | 9 +- src/app/editor/overworld/overworld_editor.h | 7 +- src/app/editor/overworld/tile16_editor.cc | 2 +- src/app/editor/overworld/tile16_editor.h | 9 +- src/app/emu/emulator.cc | 2 +- src/app/emu/video/ppu.h | 2 +- src/app/gfx/tilemap.cc | 2 +- src/app/gui/canvas.cc | 274 +++++++++---------- src/app/gui/canvas.h | 26 +- src/app/rom.cc | 2 - src/app/rom.h | 34 --- src/ios/main.mm | 14 +- 17 files changed, 256 insertions(+), 236 deletions(-) diff --git a/docs/infrastructure.md b/docs/infrastructure.md index 834ac7d1..b6300433 100644 --- a/docs/infrastructure.md +++ b/docs/infrastructure.md @@ -9,7 +9,6 @@ The goal of yaze is to build a cross platform editor for the Legend of Zelda: A - **yaze**: Desktop application for Windows/macOS/Linux - **z3ed**: Command Line Interface - **yaze_c**: C Library -- **yaze_py**: Python Module - **yaze_test**: Unit test executable - **yaze_ios**: iOS application @@ -23,7 +22,6 @@ The goal of yaze is to build a cross platform editor for the Legend of Zelda: A - **app**: Contains the GUI editor `yaze` - **app/emu**: Contains a standalone Snes emulator application `yaze_emu` - **cli**: Contains the command line interface `z3ed` - - **cli/python**: Contains the Python module `yaze_py` - **ios**: Contains the iOS application `yaze_ios` - **lib**: Contains the dependencies as git submodules - **test**: Contains testing interface `yaze_test` @@ -37,11 +35,10 @@ See [build-instructions.md](docs/build-instructions.md) for more information. - **ImGui**: GUI library - **Abseil**: C++ library - **libpng**: Image library -- **Boost**: Python library ## Flow of Control -- app/yaze.cc +- app/main.cc - Initializes `absl::FailureSignalHandler` for stack tracing. - Runs the `core::Controller` loop. - app/core/controller.cc @@ -75,8 +72,6 @@ See [build-instructions.md](docs/build-instructions.md) for more information. The Rom class provides methods to manipulate and access data from a ROM. -Currently implemented as a singleton with SharedRom which is not great but has helped with development velocity. Potential room for improvement is to refactor the editors to take the ROM as a parameter. - ## Bitmap - app/gfx/bitmap.cc diff --git a/incl/yaze.h b/incl/yaze.h index 04f38ea4..ca5ee02c 100644 --- a/incl/yaze.h +++ b/incl/yaze.h @@ -35,8 +35,6 @@ struct yaze_project { const char* name; const char* filepath; const char* rom_filename; - const char* code_folder; - const char* labels_filename; }; yaze_project yaze_load_project(const char* filename); @@ -93,14 +91,61 @@ typedef struct snes_tile32 { uint16_t t3; } snes_tile32; +/** + * @brief Get a color from a palette set. + * + * @details This function gets a color from a palette set and returns it as a + * snes_color object. + * + * @param rom The ROM to get the color from. + * @param palette_set The palette set to get the color from. + * @param palette The palette to get the color from. + * @param color The color to get from the palette. + * @return The color from the palette set. + */ snes_color yaze_get_color_from_paletteset(const zelda3_rom* rom, int palette_set, int palette, int color); +/** + * @brief Load the overworld from the ROM. + * + * @param rom The ROM to load the overworld from. + * @return The status of the operation. If the operation is successful, the + * overworld object will be populated with the overworld from the ROM. + */ zelda3_overworld* yaze_load_overworld(const zelda3_rom* rom); +/** + * @brief Load all rooms from the ROM. + * + * @details This function loads all rooms from the ROM and returns them as an + * array of rooms. + * + * @param rom The ROM to load rooms from. + * @return The status of the operation. If the operation is successful, the + * rooms array will be populated with the rooms from the ROM. + */ zelda3_dungeon_room* yaze_load_all_rooms(const zelda3_rom* rom); +/** + * @brief Load all messages from the ROM. + * + * @details This function loads all messages from the ROM and returns them as an + * array of messages. + * + * @param rom The ROM to load messages from. + * @param messages Pointer to an array of messages. + * @return The status of the operation. If the operation is successful, the + * messages array will be populated with the messages from the ROM. + */ +yaze_status yaze_load_messages(zelda3_rom* rom, zelda3_message** messages); + +/** + * @brief Function pointer to initialize the extension. + * + * @param context The editor context. + */ typedef void (*yaze_initialize_func)(yaze_editor_context* context); typedef void (*yaze_cleanup_func)(void); diff --git a/incl/zelda.h b/incl/zelda.h index f3714658..de6d4038 100644 --- a/incl/zelda.h +++ b/incl/zelda.h @@ -86,7 +86,7 @@ const static zelda3_version_pointers zelda3_jp_pointers = { typedef struct zelda3_rom { const char* filename; - const uint8_t* data; + uint8_t* data; size_t size; void* impl; // yaze::Rom* } zelda3_rom; @@ -95,6 +95,19 @@ zelda3_rom* yaze_load_rom(const char* filename); void yaze_unload_rom(zelda3_rom* rom); void yaze_save_rom(zelda3_rom* rom, const char* filename); +/** + * @brief Primitive of a message. + * + */ +typedef struct zelda3_message { + uint8_t id; + uint8_t address; + uint8_t *raw_string; + uint8_t *contents_parsed; + uint8_t *data; + uint8_t *data_parsed; +} zelda3_message; + /** * @brief Primitive of an overworld map. */ diff --git a/src/app/core/platform/app_delegate.mm b/src/app/core/platform/app_delegate.mm index de33e70e..68868ee7 100644 --- a/src/app/core/platform/app_delegate.mm +++ b/src/app/core/platform/app_delegate.mm @@ -206,15 +206,16 @@ } - (void)openFileAction:(id)sender { - if (!yaze::SharedRom::shared_rom_ - ->LoadFromFile(yaze::core::FileDialogWrapper::ShowOpenFileDialog()) - .ok()) { - NSAlert *alert = [[NSAlert alloc] init]; - [alert setMessageText:@"Error"]; - [alert setInformativeText:@"Failed to load file."]; - [alert addButtonWithTitle:@"OK"]; - [alert runModal]; - } + // TODO: Re-implmenent this without the SharedRom singleton + // if (!yaze::SharedRom::shared_rom_ + // ->LoadFromFile(yaze::core::FileDialogWrapper::ShowOpenFileDialog()) + // .ok()) { + // NSAlert *alert = [[NSAlert alloc] init]; + // [alert setMessageText:@"Error"]; + // [alert setInformativeText:@"Failed to load file."]; + // [alert addButtonWithTitle:@"OK"]; + // [alert runModal]; + // } } - (void)cutAction:(id)sender { @@ -238,12 +239,12 @@ extern "C" void yaze_initialize_cococa() { extern "C" int yaze_run_cocoa_app_delegate(const char *filename) { yaze_initialize_cococa(); - yaze::core::Controller controller; - EXIT_IF_ERROR(controller.OnEntry(filename)); - while (controller.IsActive()) { + auto controller = std::make_unique(); + EXIT_IF_ERROR(controller->OnEntry(filename)); + while (controller->IsActive()) { @autoreleasepool { - controller.OnInput(); - if (auto status = controller.OnLoad(); !status.ok()) { + controller->OnInput(); + if (auto status = controller->OnLoad(); !status.ok()) { NSAlert *alert = [[NSAlert alloc] init]; [alert setMessageText:@"Error"]; [alert setInformativeText:[NSString stringWithUTF8String:status.message().data()]]; @@ -251,10 +252,10 @@ extern "C" int yaze_run_cocoa_app_delegate(const char *filename) { [alert runModal]; break; } - controller.DoRender(); + controller->DoRender(); } } - controller.OnExit(); + controller->OnExit(); return EXIT_SUCCESS; } diff --git a/src/app/editor/graphics/gfx_group_editor.h b/src/app/editor/graphics/gfx_group_editor.h index 56a5c4d7..f10f5061 100644 --- a/src/app/editor/graphics/gfx_group_editor.h +++ b/src/app/editor/graphics/gfx_group_editor.h @@ -13,7 +13,7 @@ namespace editor { * @class GfxGroupEditor * @brief Manage graphics group configurations in a Rom. */ -class GfxGroupEditor : public SharedRom { +class GfxGroupEditor { public: absl::Status Update(); @@ -27,6 +27,8 @@ class GfxGroupEditor : public SharedRom { void SetSelectedSpriteset(uint8_t spriteset) { selected_spriteset_ = spriteset; } + void set_rom(Rom* rom) { rom_ = rom; } + Rom* rom() const { return rom_; } private: uint8_t selected_blockset_ = 0; @@ -39,6 +41,7 @@ class GfxGroupEditor : public SharedRom { gui::Canvas spriteset_canvas_; gfx::SnesPalette palette_; + Rom* rom_ = nullptr; }; } // namespace editor diff --git a/src/app/editor/overworld/overworld_editor.cc b/src/app/editor/overworld/overworld_editor.cc index 3393942c..55edb4bf 100644 --- a/src/app/editor/overworld/overworld_editor.cc +++ b/src/app/editor/overworld/overworld_editor.cc @@ -586,7 +586,9 @@ absl::Status OverworldEditor::CheckForCurrentMap() { } const int current_highlighted_map = current_map_; - current_parent_ = overworld_.overworld_map(current_map_)->parent(); + if (!current_map_lock_) { + current_parent_ = overworld_.overworld_map(current_map_)->parent(); + } if (overworld_.overworld_map(current_map_)->is_large_map() || overworld_.overworld_map(current_map_)->large_index() != 0) { @@ -613,6 +615,11 @@ absl::Status OverworldEditor::CheckForCurrentMap() { maps_bmp_[current_map_].set_modified(false); } + // If double clicked, toggle the current map + if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Right)) { + current_map_lock_ = !current_map_lock_; + } + return absl::OkStatus(); } diff --git a/src/app/editor/overworld/overworld_editor.h b/src/app/editor/overworld/overworld_editor.h index 4fb1428c..7e2659e1 100644 --- a/src/app/editor/overworld/overworld_editor.h +++ b/src/app/editor/overworld/overworld_editor.h @@ -31,7 +31,8 @@ constexpr ImVec2 kBlocksetCanvasSize(0x100 + 1, 0x4000 + 1); constexpr ImVec2 kGraphicsBinCanvasSize(0x100 + 1, kNumSheetsToLoad * 0x40 + 1); constexpr ImGuiTableFlags kOWMapFlags = - ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable; + ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | + ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp; constexpr ImGuiTableFlags kToolsetTableFlags = ImGuiTableFlags_SizingFixedFit; constexpr ImGuiTableFlags kOWEditFlags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | @@ -75,6 +76,7 @@ class OverworldEditor : public Editor, public gfx::GfxContext { public: explicit OverworldEditor(Rom* rom) : rom_(rom) { type_ = EditorType::kOverworld; + gfx_group_editor_.set_rom(rom); } void Initialize() override; @@ -212,12 +214,13 @@ class OverworldEditor : public Editor, public gfx::GfxContext { bool overworld_canvas_fullscreen_ = false; bool middle_mouse_dragging_ = false; bool is_dragging_entity_ = false; + bool current_map_lock_ = false; gfx::Tilemap tile16_blockset_; Rom* rom_; - Tile16Editor tile16_editor_{&tile16_blockset_}; + Tile16Editor tile16_editor_{rom_, &tile16_blockset_}; GfxGroupEditor gfx_group_editor_; PaletteEditor palette_editor_; diff --git a/src/app/editor/overworld/tile16_editor.cc b/src/app/editor/overworld/tile16_editor.cc index f67c02a6..ea907bb5 100644 --- a/src/app/editor/overworld/tile16_editor.cc +++ b/src/app/editor/overworld/tile16_editor.cc @@ -245,7 +245,7 @@ absl::Status Tile16Editor::DrawToCurrentTile16(ImVec2 click_position) { } absl::Status Tile16Editor::UpdateTile16Edit() { - auto ow_main_pal_group = rom()->palette_group().overworld_main; + static const auto ow_main_pal_group = rom()->palette_group().overworld_main; // Create a more organized layout with tabs if (BeginTabBar("Tile16EditorTabs")) { diff --git a/src/app/editor/overworld/tile16_editor.h b/src/app/editor/overworld/tile16_editor.h index abd7bbe9..37762dba 100644 --- a/src/app/editor/overworld/tile16_editor.h +++ b/src/app/editor/overworld/tile16_editor.h @@ -22,9 +22,10 @@ namespace editor { /** * @brief Popup window to edit Tile16 data */ -class Tile16Editor : public gfx::GfxContext, public SharedRom { +class Tile16Editor : public gfx::GfxContext { public: - Tile16Editor(gfx::Tilemap *tile16_blockset) : tile16_blockset_(tile16_blockset) {} + Tile16Editor(Rom *rom, gfx::Tilemap *tile16_blockset) + : rom_(rom), tile16_blockset_(tile16_blockset) {} absl::Status Initialize(const gfx::Bitmap &tile16_blockset_bmp, const gfx::Bitmap ¤t_gfx_bmp, std::array &all_tiles_types); @@ -52,7 +53,11 @@ class Tile16Editor : public gfx::GfxContext, public SharedRom { absl::Status LoadTile16FromScratchSpace(int slot); absl::Status ClearScratchSpace(int slot); + void set_rom(Rom *rom) { rom_ = rom; } + Rom *rom() const { return rom_; } + private: + Rom *rom_ = nullptr; bool map_blockset_loaded_ = false; bool transfer_started_ = false; bool transfer_blockset_loaded_ = false; diff --git a/src/app/emu/emulator.cc b/src/app/emu/emulator.cc index 8744fea3..1b462f74 100644 --- a/src/app/emu/emulator.cc +++ b/src/app/emu/emulator.cc @@ -4,7 +4,7 @@ #include #include "app/core/platform/file_dialog.h" -#include "app/core/platform/renderer.h" +#include "app/core/window.h" #include "app/emu/cpu/internal/opcodes.h" #include "app/gui/icons.h" #include "app/gui/input.h" diff --git a/src/app/emu/video/ppu.h b/src/app/emu/video/ppu.h index 687f277f..aed94d91 100644 --- a/src/app/emu/video/ppu.h +++ b/src/app/emu/video/ppu.h @@ -250,7 +250,7 @@ struct BackgroundLayer { bool enabled; // Whether the background layer is enabled }; -class Ppu : public SharedRom { +class Ppu { public: // Initializes the PPU with the necessary resources and dependencies Ppu(Memory& memory) : memory_(memory) {} diff --git a/src/app/gfx/tilemap.cc b/src/app/gfx/tilemap.cc index f067b71a..366d25ec 100644 --- a/src/app/gfx/tilemap.cc +++ b/src/app/gfx/tilemap.cc @@ -2,7 +2,7 @@ #include -#include "app/core/platform/renderer.h" +#include "app/core/window.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" diff --git a/src/app/gui/canvas.cc b/src/app/gui/canvas.cc index 1d521d73..bc14bf6f 100644 --- a/src/app/gui/canvas.cc +++ b/src/app/gui/canvas.cc @@ -6,14 +6,11 @@ #include "app/core/window.h" #include "app/gfx/bitmap.h" #include "app/gui/color.h" -#include "app/gui/input.h" #include "app/gui/style.h" -#include "app/rom.h" #include "imgui/imgui.h" #include "imgui_memory_editor.h" -namespace yaze { -namespace gui { +namespace yaze::gui { using core::Renderer; @@ -43,8 +40,8 @@ constexpr ImGuiButtonFlags kMouseFlags = namespace { ImVec2 AlignPosToGrid(ImVec2 pos, float scale) { - return ImVec2(std::floor((double)pos.x / scale) * scale, - std::floor((double)pos.y / scale) * scale); + return ImVec2(std::floor(pos.x / scale) * scale, + std::floor(pos.y / scale) * scale); } } // namespace @@ -62,15 +59,14 @@ void Canvas::UpdateColorPainter(gfx::Bitmap &bitmap, const ImVec4 &color, DrawOverlay(); } -void Canvas::UpdateInfoGrid(ImVec2 bg_size, int tile_size, float scale, - float grid_size, int label_id) { +void Canvas::UpdateInfoGrid(ImVec2 bg_size, float grid_size, int label_id) { enable_custom_labels_ = true; DrawBackground(bg_size); DrawInfoGrid(grid_size, 8, label_id); DrawOverlay(); } -void Canvas::DrawBackground(ImVec2 canvas_size, bool can_drag) { +void Canvas::DrawBackground(ImVec2 canvas_size) { draw_list_ = GetWindowDrawList(); canvas_p0_ = GetCursorScreenPos(); if (!custom_canvas_size_) canvas_sz_ = GetContentRegionAvail(); @@ -145,59 +141,59 @@ void Canvas::DrawContextMenu() { Text("Pitch: %d", bitmap_->surface()->pitch); Text("BitsPerPixel: %d", bitmap_->surface()->format->BitsPerPixel); Text("BytesPerPixel: %d", bitmap_->surface()->format->BytesPerPixel); - EndMenu(); - } - if (BeginMenu("Bitmap Format")) { - if (MenuItem("Indexed")) { - bitmap_->Reformat(gfx::BitmapFormat::kIndexed); - Renderer::Get().UpdateBitmap(bitmap_); - } - if (MenuItem("4BPP")) { - bitmap_->Reformat(gfx::BitmapFormat::k4bpp); - Renderer::Get().UpdateBitmap(bitmap_); - } - if (MenuItem("8BPP")) { - bitmap_->Reformat(gfx::BitmapFormat::k8bpp); - Renderer::Get().UpdateBitmap(bitmap_); - } - - EndMenu(); - } - if (BeginMenu("View Palette")) { - DisplayEditablePalette(*bitmap_->mutable_palette(), "Palette", true, 8); - EndMenu(); - } - - if (BeginMenu("Bitmap Palette")) { - if (rom()->is_loaded()) { - gui::TextWithSeparators("ROM Palette"); - ImGui::SetNextItemWidth(100.f); - ImGui::Combo("Palette Group", (int *)&edit_palette_group_name_index_, - gfx::kPaletteGroupAddressesKeys, - IM_ARRAYSIZE(gfx::kPaletteGroupAddressesKeys)); - ImGui::SetNextItemWidth(100.f); - gui::InputHexWord("Palette Group Index", &edit_palette_index_); - - auto palette_group = rom()->mutable_palette_group()->get_group( - gfx::kPaletteGroupAddressesKeys[edit_palette_group_name_index_]); - auto palette = palette_group->mutable_palette(edit_palette_index_); - - if (ImGui::BeginChild("Palette", ImVec2(0, 300), true)) { - gui::SelectablePalettePipeline(edit_palette_sub_index_, - refresh_graphics_, *palette); - - if (refresh_graphics_) { - bitmap_->SetPaletteWithTransparent(*palette, - edit_palette_sub_index_); - Renderer::Get().UpdateBitmap(bitmap_); - refresh_graphics_ = false; - } - ImGui::EndChild(); + MenuItem("Data", nullptr, &show_bitmap_data); + if (BeginMenu("Format")) { + if (MenuItem("Indexed")) { + bitmap_->Reformat(gfx::BitmapFormat::kIndexed); + Renderer::Get().UpdateBitmap(bitmap_); } + if (MenuItem("4BPP")) { + bitmap_->Reformat(gfx::BitmapFormat::k4bpp); + Renderer::Get().UpdateBitmap(bitmap_); + } + if (MenuItem("8BPP")) { + bitmap_->Reformat(gfx::BitmapFormat::k8bpp); + Renderer::Get().UpdateBitmap(bitmap_); + } + + EndMenu(); + } + if (BeginMenu("Change Palette")) { + Text("Work in progress"); + // TODO: Get ROM data for change palette + // gui::TextWithSeparators("ROM Palette"); + // ImGui::SetNextItemWidth(100.f); + // ImGui::Combo("Palette Group", (int *)&edit_palette_group_name_index_, + // gfx::kPaletteGroupAddressesKeys, + // IM_ARRAYSIZE(gfx::kPaletteGroupAddressesKeys)); + // ImGui::SetNextItemWidth(100.f); + // gui::InputHexWord("Palette Group Index", &edit_palette_index_); + + // auto palette_group = rom()->mutable_palette_group()->get_group( + // gfx::kPaletteGroupAddressesKeys[edit_palette_group_name_index_]); + // auto palette = palette_group->mutable_palette(edit_palette_index_); + + // if (ImGui::BeginChild("Palette", ImVec2(0, 300), true)) { + // gui::SelectablePalettePipeline(edit_palette_sub_index_, + // refresh_graphics_, *palette); + + // if (refresh_graphics_) { + // bitmap_->SetPaletteWithTransparent(*palette, + // edit_palette_sub_index_); + // Renderer::Get().UpdateBitmap(bitmap_); + // refresh_graphics_ = false; + // } + // ImGui::EndChild(); + // } + EndMenu(); + } + if (BeginMenu("View Palette")) { + DisplayEditablePalette(*bitmap_->mutable_palette(), "Palette", true, + 8); + EndMenu(); } EndMenu(); } - MenuItem("Bitmap Data", nullptr, &show_bitmap_data); } ImGui::Separator(); if (BeginMenu("Grid Tile Size")) { @@ -255,12 +251,8 @@ bool Canvas::DrawTilePainter(const Bitmap &bitmap, int size, float scale) { origin.y + paint_pos.y + scaled_size)); } - if (IsMouseClicked(ImGuiMouseButton_Left)) { - // Draw the currently selected tile on the overworld here - // Save the coordinates of the selected tile. - drawn_tile_pos_ = paint_pos; - return true; - } else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) { + if (IsMouseClicked(ImGuiMouseButton_Left) && + ImGui::IsMouseDragging(ImGuiMouseButton_Left)) { // Draw the currently selected tile on the overworld here // Save the coordinates of the selected tile. drawn_tile_pos_ = paint_pos; @@ -308,10 +300,8 @@ bool Canvas::DrawTilemapPainter(gfx::Tilemap &tilemap, int current_tile) { ImVec2(origin.x + paint_pos.x + scaled_size, origin.y + paint_pos.y + scaled_size)); - if (IsMouseClicked(ImGuiMouseButton_Left)) { - drawn_tile_pos_ = paint_pos; - return true; - } else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) { + if (IsMouseClicked(ImGuiMouseButton_Left) || + ImGui::IsMouseDragging(ImGuiMouseButton_Left)) { drawn_tile_pos_ = paint_pos; return true; } @@ -407,9 +397,7 @@ bool Canvas::DrawTileSelector(int size, int size_y) { if (!points_.empty()) { points_.clear(); } - ImVec2 painter_pos; - painter_pos.x = std::floor((double)mouse_pos.x / size) * size; - painter_pos.y = std::floor((double)mouse_pos.y / size) * size; + ImVec2 painter_pos = AlignPosToGrid(mouse_pos, size); points_.push_back(painter_pos); points_.push_back(ImVec2(painter_pos.x + size, painter_pos.y + size_y)); @@ -464,50 +452,48 @@ void Canvas::DrawSelectRect(int current_map, int tile_size, float scale) { dragging = true; } - if (dragging) { + if (dragging && !ImGui::IsMouseDown(ImGuiMouseButton_Right)) { // Release dragging mode - if (!ImGui::IsMouseDown(ImGuiMouseButton_Right)) { - dragging = false; + dragging = false; - // Calculate the bounds of the rectangle in terms of 16x16 tile indices - constexpr int tile16_size = 16; - int start_x = std::floor(drag_start_pos.x / scaled_size) * tile16_size; - int start_y = std::floor(drag_start_pos.y / scaled_size) * tile16_size; - int end_x = std::floor(drag_end_pos.x / scaled_size) * tile16_size; - int end_y = std::floor(drag_end_pos.y / scaled_size) * tile16_size; + // Calculate the bounds of the rectangle in terms of 16x16 tile indices + constexpr int tile16_size = 16; + int start_x = std::floor(drag_start_pos.x / scaled_size) * tile16_size; + int start_y = std::floor(drag_start_pos.y / scaled_size) * tile16_size; + int end_x = std::floor(drag_end_pos.x / scaled_size) * tile16_size; + int end_y = std::floor(drag_end_pos.y / scaled_size) * tile16_size; - // Swap the start and end positions if they are in the wrong order - if (start_x > end_x) std::swap(start_x, end_x); - if (start_y > end_y) std::swap(start_y, end_y); + // Swap the start and end positions if they are in the wrong order + if (start_x > end_x) std::swap(start_x, end_x); + if (start_y > end_y) std::swap(start_y, end_y); - selected_tiles_.clear(); - // Number of tiles per local map (since each tile is 16x16) - constexpr int tiles_per_local_map = small_map_size / 16; + selected_tiles_.clear(); + // Number of tiles per local map (since each tile is 16x16) + constexpr int tiles_per_local_map = small_map_size / 16; - // Loop through the tiles in the rectangle and store their positions - for (int y = start_y; y <= end_y; y += tile16_size) { - for (int x = start_x; x <= end_x; x += tile16_size) { - // Determine which local map (512x512) the tile is in - int local_map_x = x / small_map_size; - int local_map_y = y / small_map_size; + // Loop through the tiles in the rectangle and store their positions + for (int y = start_y; y <= end_y; y += tile16_size) { + for (int x = start_x; x <= end_x; x += tile16_size) { + // Determine which local map (512x512) the tile is in + int local_map_x = x / small_map_size; + int local_map_y = y / small_map_size; - // Calculate the tile's position within its local map - int tile16_x = (x % small_map_size) / tile16_size; - int tile16_y = (y % small_map_size) / tile16_size; + // Calculate the tile's position within its local map + int tile16_x = (x % small_map_size) / tile16_size; + int tile16_y = (y % small_map_size) / tile16_size; - // Calculate the index within the overall map structure - int index_x = local_map_x * tiles_per_local_map + tile16_x; - int index_y = local_map_y * tiles_per_local_map + tile16_y; + // Calculate the index within the overall map structure + int index_x = local_map_x * tiles_per_local_map + tile16_x; + int index_y = local_map_y * tiles_per_local_map + tile16_y; - selected_tiles_.push_back(ImVec2(index_x, index_y)); - } + selected_tiles_.push_back(ImVec2(index_x, index_y)); } - // Clear and add the calculated rectangle points - selected_points_.clear(); - selected_points_.push_back(drag_start_pos); - selected_points_.push_back(drag_end_pos); - select_rect_active_ = true; } + // Clear and add the calculated rectangle points + selected_points_.clear(); + selected_points_.push_back(drag_start_pos); + selected_points_.push_back(drag_end_pos); + select_rect_active_ = true; } } @@ -709,25 +695,27 @@ void Canvas::DrawInfoGrid(float grid_step, int tile_id_offset, int label_id) { DrawGridLines(grid_step); DrawCustomHighlight(grid_step); - if (enable_custom_labels_) { - // Draw the contents of labels on the grid - for (float x = fmodf(scrolling_.x, grid_step); - x < canvas_sz_.x * global_scale_; x += grid_step) { - for (float y = fmodf(scrolling_.y, grid_step); - y < canvas_sz_.y * global_scale_; y += grid_step) { - int tile_x = (x - scrolling_.x) / grid_step; - int tile_y = (y - scrolling_.y) / grid_step; - int tile_id = tile_x + (tile_y * tile_id_offset); + if (!enable_custom_labels_) { + return; + } - if (tile_id >= labels_[label_id].size()) { - break; - } - std::string label = labels_[label_id][tile_id]; - draw_list_->AddText( - ImVec2(canvas_p0_.x + x + (grid_step / 2) - tile_id_offset, - canvas_p0_.y + y + (grid_step / 2) - tile_id_offset), - kWhiteColor, label.data()); + // Draw the contents of labels on the grid + for (float x = fmodf(scrolling_.x, grid_step); + x < canvas_sz_.x * global_scale_; x += grid_step) { + for (float y = fmodf(scrolling_.y, grid_step); + y < canvas_sz_.y * global_scale_; y += grid_step) { + int tile_x = (x - scrolling_.x) / grid_step; + int tile_y = (y - scrolling_.y) / grid_step; + int tile_id = tile_x + (tile_y * tile_id_offset); + + if (tile_id >= labels_[label_id].size()) { + break; } + std::string label = labels_[label_id][tile_id]; + draw_list_->AddText( + ImVec2(canvas_p0_.x + x + (grid_step / 2) - tile_id_offset, + canvas_p0_.y + y + (grid_step / 2) - tile_id_offset), + kWhiteColor, label.data()); } } } @@ -773,25 +761,26 @@ void Canvas::DrawGrid(float grid_step, int tile_id_offset) { } } - if (enable_custom_labels_) { - // Draw the contents of labels on the grid - for (float x = fmodf(scrolling_.x, grid_step); - x < canvas_sz_.x * global_scale_; x += grid_step) { - for (float y = fmodf(scrolling_.y, grid_step); - y < canvas_sz_.y * global_scale_; y += grid_step) { - int tile_x = (x - scrolling_.x) / grid_step; - int tile_y = (y - scrolling_.y) / grid_step; - int tile_id = tile_x + (tile_y * tile_id_offset); + if (!enable_custom_labels_) { + return; + } + // Draw the contents of labels on the grid + for (float x = fmodf(scrolling_.x, grid_step); + x < canvas_sz_.x * global_scale_; x += grid_step) { + for (float y = fmodf(scrolling_.y, grid_step); + y < canvas_sz_.y * global_scale_; y += grid_step) { + int tile_x = (x - scrolling_.x) / grid_step; + int tile_y = (y - scrolling_.y) / grid_step; + int tile_id = tile_x + (tile_y * tile_id_offset); - if (tile_id >= labels_[current_labels_].size()) { - break; - } - std::string label = labels_[current_labels_][tile_id]; - draw_list_->AddText( - ImVec2(canvas_p0_.x + x + (grid_step / 2) - tile_id_offset, - canvas_p0_.y + y + (grid_step / 2) - tile_id_offset), - kWhiteColor, label.data()); + if (tile_id >= labels_[current_labels_].size()) { + break; } + std::string label = labels_[current_labels_][tile_id]; + draw_list_->AddText( + ImVec2(canvas_p0_.x + x + (grid_step / 2) - tile_id_offset, + canvas_p0_.y + y + (grid_step / 2) - tile_id_offset), + kWhiteColor, label.data()); } } } @@ -909,8 +898,8 @@ void GraphicsBinCanvasPipeline(int width, int height, int tile_size, void BitmapCanvasPipeline(gui::Canvas &canvas, gfx::Bitmap &bitmap, int width, int height, int tile_size, bool is_loaded, bool scrollbar, int canvas_id) { - auto draw_canvas = [](gui::Canvas &canvas, gfx::Bitmap &bitmap, int width, - int height, int tile_size, bool is_loaded) { + auto draw_canvas = [&](gui::Canvas &canvas, gfx::Bitmap &bitmap, int width, + int height, int tile_size, bool is_loaded) { canvas.DrawBackground(ImVec2(width + 1, height + 1)); canvas.DrawContextMenu(); canvas.DrawBitmap(bitmap, 2, is_loaded); @@ -932,5 +921,4 @@ void BitmapCanvasPipeline(gui::Canvas &canvas, gfx::Bitmap &bitmap, int width, } } -} // namespace gui -} // namespace yaze +} // namespace yaze::gui diff --git a/src/app/gui/canvas.h b/src/app/gui/canvas.h index 61c74b9d..24d3ec70 100644 --- a/src/app/gui/canvas.h +++ b/src/app/gui/canvas.h @@ -34,28 +34,28 @@ enum class CanvasGridSize { k8x8, k16x16, k32x32, k64x64 }; * on a canvas. It supports features such as bitmap drawing, context menu * handling, tile painting, custom grid, and more. */ -class Canvas : public SharedRom { +class Canvas { public: Canvas() = default; explicit Canvas(const std::string &id) : canvas_id_(id) { context_id_ = id + "Context"; } explicit Canvas(const std::string &id, ImVec2 canvas_size) - : canvas_id_(id), custom_canvas_size_(true), canvas_sz_(canvas_size) { + : custom_canvas_size_(true), canvas_sz_(canvas_size), canvas_id_(id) { context_id_ = id + "Context"; } explicit Canvas(const std::string &id, ImVec2 canvas_size, CanvasGridSize grid_size) - : canvas_id_(id), custom_canvas_size_(true), canvas_sz_(canvas_size) { + : custom_canvas_size_(true), canvas_sz_(canvas_size), canvas_id_(id) { context_id_ = id + "Context"; SetCanvasGridSize(grid_size); } explicit Canvas(const std::string &id, ImVec2 canvas_size, CanvasGridSize grid_size, float global_scale) - : canvas_id_(id), - custom_canvas_size_(true), + : custom_canvas_size_(true), + global_scale_(global_scale), canvas_sz_(canvas_size), - global_scale_(global_scale) { + canvas_id_(id) { context_id_ = id + "Context"; SetCanvasGridSize(grid_size); } @@ -81,12 +81,12 @@ class Canvas : public SharedRom { const std::function &event, int tile_size, float scale = 1.0f); - void UpdateInfoGrid(ImVec2 bg_size, int tile_size, float scale = 1.0f, - float grid_size = 64.0f, int label_id = 0); + void UpdateInfoGrid(ImVec2 bg_size, float grid_size = 64.0f, + int label_id = 0); // Background for the Canvas represents region without any content drawn to // it, but can be controlled by the user. - void DrawBackground(ImVec2 canvas_size = ImVec2(0, 0), bool drag = false); + void DrawBackground(ImVec2 canvas_size = ImVec2(0, 0)); // Context Menu refers to what happens when the right mouse button is pressed // This routine also handles the scrolling for the canvas. @@ -111,8 +111,8 @@ class Canvas : public SharedRom { // Draws the contents of the Bitmap image to the Canvas void DrawBitmap(Bitmap &bitmap, int border_offset, float scale); - void DrawBitmap(Bitmap &bitmap, int x_offset, int y_offset, float scale = 1.0f, - int alpha = 255); + void DrawBitmap(Bitmap &bitmap, int x_offset, int y_offset, + float scale = 1.0f, int alpha = 255); void DrawBitmap(Bitmap &bitmap, ImVec2 dest_pos, ImVec2 dest_size, ImVec2 src_pos, ImVec2 src_size); void DrawBitmapTable(const BitmapTable &gfx_bin); @@ -206,6 +206,9 @@ class Canvas : public SharedRom { auto hover_mouse_pos() const { return mouse_pos_in_canvas_; } + void set_rom(Rom *rom) { rom_ = rom; } + Rom *rom() const { return rom_; } + private: bool draggable_ = false; bool is_hovered_ = false; @@ -228,6 +231,7 @@ class Canvas : public SharedRom { uint64_t edit_palette_sub_index_ = 0; Bitmap *bitmap_ = nullptr; + Rom *rom_ = nullptr; ImDrawList *draw_list_ = nullptr; diff --git a/src/app/rom.cc b/src/app/rom.cc index 6b4270da..1d4af0ef 100644 --- a/src/app/rom.cc +++ b/src/app/rom.cc @@ -649,6 +649,4 @@ absl::Status Rom::WriteColor(uint32_t address, const gfx::SnesColor &color) { return WriteShort(address, bgr); } -std::shared_ptr SharedRom::shared_rom_ = nullptr; - } // namespace yaze diff --git a/src/app/rom.h b/src/app/rom.h index f9256408..c917d59a 100644 --- a/src/app/rom.h +++ b/src/app/rom.h @@ -272,40 +272,6 @@ absl::StatusOr> LoadLinkGraphics( absl::StatusOr LoadFontGraphics(const Rom& rom); -/** - * @brief A class to hold a shared pointer to a Rom object. - */ -class SharedRom { - public: - SharedRom() = default; - virtual ~SharedRom() = default; - - std::shared_ptr shared_rom() { - if (!shared_rom_) { - shared_rom_ = std::make_shared(); - } - return shared_rom_; - } - - auto rom() { - if (!shared_rom_) { - shared_rom_ = std::make_shared(); - } - Rom* rom = shared_rom_.get(); - return rom; - } - - static void set_rom(Rom* rom) { - if (!shared_rom_) { - shared_rom_ = std::make_shared(); - } - shared_rom_ = std::shared_ptr(rom); - } - - // private: - static std::shared_ptr shared_rom_; -}; - } // namespace yaze #endif diff --git a/src/ios/main.mm b/src/ios/main.mm index 4711e663..dc1871f6 100644 --- a/src/ios/main.mm +++ b/src/ios/main.mm @@ -77,14 +77,6 @@ // Enable native IME. SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); - if (!_controller->CreateWindow().ok()) { - printf("Error creating window: %s\n", SDL_GetError()); - abort(); - } - if (!_controller->CreateRenderer().ok()) { - printf("Error creating renderer: %s\n", SDL_GetError()); - abort(); - } ImGui_ImplSDL2_InitForSDLRenderer(_controller->window(), yaze::core::Renderer::Get().renderer()); @@ -93,7 +85,6 @@ if (!LoadPackageFonts().ok()) { abort(); } - _controller->Initialize(""); _controller->set_active(true); _hoverGestureRecognizer = @@ -357,9 +348,10 @@ rom_data.resize(size); std::copy(bytes, bytes + size, rom_data.begin()); - PRINT_IF_ERROR(yaze::SharedRom::shared_rom_->LoadFromData(rom_data)); + // TODO: Re-implmenent this without the SharedRom singleton + // PRINT_IF_ERROR(yaze::SharedRom::shared_rom_->LoadFromData(rom_data)); std::string filename = std::string([selectedFileURL.path UTF8String]); - yaze::SharedRom::shared_rom_->set_filename(filename); + // yaze::SharedRom::shared_rom_->set_filename(filename); [selectedFileURL stopAccessingSecurityScopedResource]; } else {