From df1cdb22f5a52bf69a761b05e7e161c8d3fba4ae Mon Sep 17 00:00:00 2001 From: scawful Date: Fri, 26 Jan 2024 23:18:26 -0500 Subject: [PATCH] housekeeping and todos --- src/app/editor/overworld_editor.cc | 92 +++++++++++++++++++++++++++++- src/app/editor/overworld_editor.h | 16 ++++-- src/app/gui/canvas.cc | 15 +++-- src/app/gui/canvas.h | 4 +- src/app/gui/input.cc | 8 +-- src/app/rom.h | 47 +++++++++++++-- 6 files changed, 158 insertions(+), 24 deletions(-) diff --git a/src/app/editor/overworld_editor.cc b/src/app/editor/overworld_editor.cc index 502bb2f3..15159da3 100644 --- a/src/app/editor/overworld_editor.cc +++ b/src/app/editor/overworld_editor.cc @@ -55,6 +55,44 @@ absl::Status OverworldEditor::Update() { map_blockset_loaded_ = false; } + // TODO: Setup pan tool with middle mouse button + // if (ImGui::IsMouseDragging(ImGuiMouseButton_Middle)) { + // previous_mode = current_mode; + // current_mode = EditingMode::PAN; + // ow_map_canvas_.set_draggable(true); + // middle_mouse_dragging_ = true; + // } + // if (ImGui::IsMouseReleased(ImGuiMouseButton_Middle) && + // current_mode == EditingMode::PAN && middle_mouse_dragging_) { + // current_mode = previous_mode; + // ow_map_canvas_.set_draggable(false); + // middle_mouse_dragging_ = false; + // } + + if (overworld_canvas_fullscreen_) { + static bool use_work_area = true; + static ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | + ImGuiWindowFlags_NoMove | + ImGuiWindowFlags_NoSavedSettings; + + // We demonstrate using the full viewport area or the work area (without + // menu-bars, task-bars etc.) Based on your use case you may want one or the + // other. + const ImGuiViewport *viewport = ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(use_work_area ? viewport->WorkPos : viewport->Pos); + ImGui::SetNextWindowSize(use_work_area ? viewport->WorkSize + : viewport->Size); + + if (ImGui::Begin("Example: Fullscreen window", + &overworld_canvas_fullscreen_, flags)) { + // Draws the toolset for editing the Overworld. + RETURN_IF_ERROR(DrawToolset()) + DrawOverworldCanvas(); + } + ImGui::End(); + return absl::OkStatus(); + } + TAB_BAR("##OWEditorTabBar") TAB_ITEM("Map Editor") status_ = UpdateOverworldEdit(); @@ -187,7 +225,7 @@ absl::Status OverworldEditor::DrawToolset() { static bool show_gfx_group = false; static bool show_properties = false; - if (BeginTable("OWToolset", 20, kToolsetTableFlags, ImVec2(0, 0))) { + if (BeginTable("OWToolset", 22, kToolsetTableFlags, ImVec2(0, 0))) { for (const auto &name : kToolsetColumnNames) ImGui::TableSetupColumn(name.data()); @@ -213,8 +251,22 @@ absl::Status OverworldEditor::DrawToolset() { ow_map_canvas_.ZoomIn(); } + NEXT_COLUMN() + if (ImGui::Button(ICON_MD_OPEN_IN_FULL)) { + overworld_canvas_fullscreen_ = !overworld_canvas_fullscreen_; + } + HOVER_HINT("Fullscreen Canvas") + TEXT_COLUMN(ICON_MD_MORE_VERT) // Separator + NEXT_COLUMN() + if (ImGui::Selectable(ICON_MD_PAN_TOOL_ALT, + current_mode == EditingMode::PAN)) { + current_mode = EditingMode::PAN; + ow_map_canvas_.set_draggable(true); + } + HOVER_HINT("Pan (Right click and drag)") + NEXT_COLUMN() if (ImGui::Selectable(ICON_MD_DRAW, current_mode == EditingMode::DRAW_TILE)) { @@ -946,7 +998,11 @@ void OverworldEditor::DrawOverworldCanvas() { gui::BeginChildBothScrollbars(7); ow_map_canvas_.DrawBackground(); gui::EndNoPadding(); - ow_map_canvas_.DrawContextMenu(); + if (current_mode == EditingMode::PAN) { + ow_map_canvas_.DrawContextMenu(); + } else { + ow_map_canvas_.set_draggable(false); + } if (overworld_.is_loaded()) { DrawOverworldMaps(); DrawOverworldEntrances(ow_map_canvas_.zero_point(), @@ -1134,6 +1190,8 @@ absl::Status OverworldEditor::LoadSpriteGraphics() { absl::Status OverworldEditor::DrawExperimentalModal() { ImGui::Begin("Experimental", &show_experimental); + DrawDebugWindow(); + gui::TextWithSeparators("PROTOTYPE OVERWORLD TILEMAP LOADER"); Text("Please provide two files:"); Text("One based on MAPn.DAT, which represents the overworld tilemap"); @@ -1178,6 +1236,36 @@ absl::Status OverworldEditor::DrawExperimentalModal() { return absl::OkStatus(); } +void OverworldEditor::DrawDebugWindow() { + ImGui::Text("Current Map: %d", current_map_); + ImGui::Text("Current Tile16: %d", current_tile16_); + int relative_x = (int)ow_map_canvas_.drawn_tile_position().x % 512; + int relative_y = (int)ow_map_canvas_.drawn_tile_position().y % 512; + ImGui::Text("Current Tile16 Drawn Position (Relative): %d, %d", relative_x, + relative_y); + + // Print the size of the overworld map_tiles per world + ImGui::Text("Light World Map Tiles: %d", + overworld_.mutable_map_tiles()->light_world.size()); + ImGui::Text("Dark World Map Tiles: %d", + overworld_.mutable_map_tiles()->dark_world.size()); + ImGui::Text("Special World Map Tiles: %d", + overworld_.mutable_map_tiles()->special_world.size()); + + static bool view_lw_map_tiles = false; + static MemoryEditor mem_edit; + // Let's create buttons which let me view containers in the memory editor + if (ImGui::Button("View Light World Map Tiles")) { + view_lw_map_tiles = !view_lw_map_tiles; + } + + if (view_lw_map_tiles) { + mem_edit.DrawContents( + overworld_.mutable_map_tiles()->light_world[current_map_].data(), + overworld_.mutable_map_tiles()->light_world[current_map_].size()); + } +} + } // namespace editor } // namespace app } // namespace yaze \ No newline at end of file diff --git a/src/app/editor/overworld_editor.h b/src/app/editor/overworld_editor.h index 48c25df0..1480bc5b 100644 --- a/src/app/editor/overworld_editor.h +++ b/src/app/editor/overworld_editor.h @@ -36,10 +36,10 @@ static constexpr uint kTile8DisplayHeight = 64; static constexpr float kInputFieldSize = 30.f; static constexpr absl::string_view kToolsetColumnNames[] = { - "#undoTool", "#redoTool", "#drawTool", "#separator2", - "#zoomOutTool", "#zoomInTool", "#separator", "#history", - "#entranceTool", "#exitTool", "#itemTool", "#spriteTool", - "#transportTool", "#musicTool", "#separator3", "#tilemapTool", + "#undoTool", "#redoTool", "#separator2", "#zoomOutTool", + "#zoomInTool", "#separator", "#drawTool", "#history", + "#entranceTool", "#exitTool", "#itemTool", "#spriteTool", + "#transportTool", "#musicTool", "#separator3", "#tilemapTool", "propertiesTool"}; constexpr ImGuiTableFlags kOWMapFlags = ImGuiTableFlags_Borders; @@ -126,6 +126,8 @@ class OverworldEditor : public Editor, absl::Status LoadSpriteGraphics(); absl::Status DrawExperimentalModal(); + void DrawDebugWindow(); + auto gfx_group_editor() const { return gfx_group_editor_; } enum class EditingMode { @@ -135,10 +137,12 @@ class OverworldEditor : public Editor, ITEMS, SPRITES, TRANSPORTS, - MUSIC + MUSIC, + PAN }; EditingMode current_mode = EditingMode::DRAW_TILE; + EditingMode previous_mode = EditingMode::DRAW_TILE; int current_world_ = 0; int current_map_ = 0; @@ -171,6 +175,8 @@ class OverworldEditor : public Editor, bool is_dragging_entrance_ = false; bool show_tile16_editor_ = false; bool show_gfx_group_editor_ = false; + bool overworld_canvas_fullscreen_ = false; + bool middle_mouse_dragging_ = false; bool IsMouseHoveringOverEntrance(const zelda3::OverworldEntrance &entrance, ImVec2 canvas_p, ImVec2 scrolling); diff --git a/src/app/gui/canvas.cc b/src/app/gui/canvas.cc index de9ed909..952a575f 100644 --- a/src/app/gui/canvas.cc +++ b/src/app/gui/canvas.cc @@ -78,7 +78,7 @@ void Canvas::DrawBackground(ImVec2 canvas_size, bool can_drag) { ImVec2(canvas_sz_.x * global_scale_, canvas_sz_.y * global_scale_); ImGui::InvisibleButton("canvas", scaled_sz, kMouseFlags); - if (can_drag) { + if (draggable_ && ImGui::IsItemHovered()) { const bool is_active = ImGui::IsItemActive(); // Held const ImVec2 origin(canvas_p0_.x + scrolling_.x, canvas_p0_.y + scrolling_.y); // Lock scrolled origin @@ -87,8 +87,9 @@ void Canvas::DrawBackground(ImVec2 canvas_size, bool can_drag) { // Pan (we use a zero mouse threshold when there's no context menu) if (const float mouse_threshold_for_pan = enable_context_menu_ ? -1.0f : 0.0f; - is_active && ImGui::IsMouseDragging(ImGuiMouseButton_Right, - mouse_threshold_for_pan)) { + is_active && + ImGui::IsMouseDragging(ImGuiMouseButton_Right, + mouse_threshold_for_pan)) { scrolling_.x += io.MouseDelta.x; scrolling_.y += io.MouseDelta.y; } @@ -110,12 +111,12 @@ void Canvas::DrawContextMenu() { // Contents of the Context Menu if (ImGui::BeginPopup("context")) { - ImGui::MenuItem("Show Grid", nullptr, &enable_grid_); - ImGui::Selectable("Show Labels", &enable_hex_tile_labels_); if (ImGui::MenuItem("Reset Position", nullptr, false)) { scrolling_.x = 0; scrolling_.y = 0; } + ImGui::MenuItem("Show Grid", nullptr, &enable_grid_); + ImGui::Selectable("Show Labels", &enable_hex_tile_labels_); if (ImGui::BeginMenu("Canvas Properties")) { ImGui::Text("Canvas Size: %.0f x %.0f", canvas_sz_.x, canvas_sz_.y); ImGui::Text("Global Scale: %.1f", global_scale_); @@ -193,9 +194,7 @@ bool Canvas::DrawTilePainter(const Bitmap &bitmap, int size, float scale) { if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { // Draw the currently selected tile on the overworld here // Save the coordinates of the selected tile. - drawn_tile_pos_ = io.MousePos; - SDL_Log("Drawn tile position: %.0f, %.0f", drawn_tile_pos_.x, - drawn_tile_pos_.y); + drawn_tile_pos_ = painter_pos; return true; } diff --git a/src/app/gui/canvas.h b/src/app/gui/canvas.h index d986738a..b8081786 100644 --- a/src/app/gui/canvas.h +++ b/src/app/gui/canvas.h @@ -142,15 +142,17 @@ class Canvas { int num_rows = height() / custom_step_; int tile_id = (x / custom_step_) + (y / custom_step_) * num_columns; if (tile_id >= num_columns * num_rows) { - tile_id = -1; // Invalid tile ID + tile_id = -1; // Invalid tile ID } return tile_id; } auto set_current_labels(int i) { current_labels_ = i; } auto set_highlight_tile_id(int i) { highlight_tile_id = i; } + auto set_draggable(bool value) { draggable_ = value; } private: + bool draggable_ = false; bool enable_grid_ = true; bool enable_hex_tile_labels_ = false; bool enable_custom_labels_ = false; diff --git a/src/app/gui/input.cc b/src/app/gui/input.cc index 2309bb8f..3700b9b3 100644 --- a/src/app/gui/input.cc +++ b/src/app/gui/input.cc @@ -45,7 +45,9 @@ bool InputScalarLeft(const char* label, ImGuiDataType data_type, void* p_data, value_changed = DataTypeApplyFromText(buf, data_type, p_data, format); } else { const float button_size = GetFrameHeight(); - + ImGui::AlignTextToFramePadding(); + ImGui::Text("%s", label); + ImGui::SameLine(); BeginGroup(); // The only purpose of the group here is to allow the caller // to query item data e.g. IsItemActive() PushID(label); @@ -57,9 +59,7 @@ bool InputScalarLeft(const char* label, ImGuiDataType data_type, void* p_data, ImVec2{style.ItemSpacing.x, style.ItemSpacing.y}); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2{style.FramePadding.x, style.FramePadding.y}); - ImGui::AlignTextToFramePadding(); - ImGui::Text("%s", label); - ImGui::SameLine(); + ImGui::SetNextItemWidth(input_width); if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID diff --git a/src/app/rom.h b/src/app/rom.h index f4f508bd..3a3e33c9 100644 --- a/src/app/rom.h +++ b/src/app/rom.h @@ -133,7 +133,8 @@ constexpr uint32_t gfx_groups_pointer = 0x6237; struct WriteAction { int address; - std::variant, gfx::SNESColor> + std::variant, gfx::SNESColor, + std::vector> value; }; @@ -147,9 +148,22 @@ class ROM : public core::ExperimentFlags { return status; } + template + absl::Status RunTransactionV2(int address, T& var, Args&&... args) { + absl::Status status = WriteHelperV2(var, address); + if (!status.ok()) { + return status; + } + + if constexpr (sizeof...(args) > 0) { + status = WriteHelperV2(std::forward(args)...); + } + + return status; + } + absl::Status WriteHelper(const WriteAction& action) { - if (std::holds_alternative(action.value) || - std::holds_alternative(action.value)) { + if (std::holds_alternative(action.value)) { return Write(action.address, std::get(action.value)); } else if (std::holds_alternative(action.value)) { return WriteShort(action.address, std::get(action.value)); @@ -158,8 +172,33 @@ class ROM : public core::ExperimentFlags { std::get>(action.value)); } else if (std::holds_alternative(action.value)) { return WriteColor(action.address, std::get(action.value)); + } else if (std::holds_alternative>( + action.value)) { + return absl::UnimplementedError( + "WriteHelper: std::vector"); } - return absl::InvalidArgumentError("Invalid write argument type"); + auto error_message = absl::StrFormat("Invalid write argument type: %s", + typeid(action.value).name()); + return absl::InvalidArgumentError(error_message); + } + + template + absl::Status WriteHelperV2(int address, T& var) { + if constexpr (std::is_same_v) { + return Write(address, var); + } else if constexpr (std::is_same_v) { + return WriteShort(address, var); + } else if constexpr (std::is_same_v>) { + return WriteVector(address, var); + } else if constexpr (std::is_same_v) { + return WriteColor(address, var); + } else if constexpr (std::is_same_v>) { + return absl::UnimplementedError( + "WriteHelperV2: std::vector"); + } + auto error_message = + absl::StrFormat("Invalid write argument type: %s", typeid(T).name()); + return absl::InvalidArgumentError(error_message); } template