From 51b4c167d579dc9900a07d4a8b0ef9f192713ec9 Mon Sep 17 00:00:00 2001 From: scawful Date: Tue, 30 Jan 2024 23:55:23 -0500 Subject: [PATCH] Canvas DrawSelectRect + DrawBitmapGroup for Tile16 selection --- src/app/gui/canvas.cc | 277 ++++++++++++++++++++++++------------------ src/app/gui/canvas.h | 27 ++-- 2 files changed, 172 insertions(+), 132 deletions(-) diff --git a/src/app/gui/canvas.cc b/src/app/gui/canvas.cc index 80f43ab0..3876fde4 100644 --- a/src/app/gui/canvas.cc +++ b/src/app/gui/canvas.cc @@ -308,22 +308,6 @@ bool Canvas::DrawTileSelector(int size) { return false; } -bool Canvas::HandleTileEdits(Canvas &blockset_canvas, - std::vector &source_blockset, - int ¤t_tile, float scale, - int tile_painter_size, int tiles_per_row) { - if (!blockset_canvas.points().empty()) { - uint16_t x = blockset_canvas.points().front().x / 32; - uint16_t y = blockset_canvas.points().front().y / 32; - current_tile = x + (y * tiles_per_row); - if (DrawTilePainter(source_blockset[current_tile], tile_painter_size, - scale)) { - return true; - } - } - return false; -} - void Canvas::DrawBitmap(const Bitmap &bitmap, int border_offset, bool ready) { if (ready) { draw_list_->AddImage( @@ -343,14 +327,15 @@ void Canvas::DrawBitmap(const Bitmap &bitmap, int border_offset, float scale) { } void Canvas::DrawBitmap(const Bitmap &bitmap, int x_offset, int y_offset, - float scale) { + float scale, int alpha) { draw_list_->AddImage( (void *)bitmap.texture(), ImVec2(canvas_p0_.x + x_offset + scrolling_.x, canvas_p0_.y + y_offset + scrolling_.y), ImVec2( canvas_p0_.x + x_offset + scrolling_.x + (bitmap.width() * scale), - canvas_p0_.y + y_offset + scrolling_.y + (bitmap.height() * scale))); + canvas_p0_.y + y_offset + scrolling_.y + (bitmap.height() * scale)), + ImVec2(0, 0), ImVec2(1, 1), IM_COL32(255, 255, 255, alpha)); } // TODO: Add parameters for sizing and positioning @@ -392,85 +377,6 @@ void Canvas::DrawOutlineWithColor(int x, int y, int w, int h, uint32_t color) { draw_list_->AddRect(origin, size, color); } -namespace { -std::vector GetTileIDsInGrid(int start_x, int start_y, int width, - int height, int tile_size) { - std::vector tile_ids; - - int num_tiles_x = width / tile_size; - int num_tiles_y = height / tile_size; - - for (int y = 0; y < num_tiles_y; y++) { - for (int x = 0; x < num_tiles_x; x++) { - int tile_id = (start_y / tile_size + y) * (width / tile_size) + - (start_x / tile_size + x); - tile_ids.push_back(tile_id); - } - } - - return tile_ids; -} -} // namespace - -void Canvas::DrawSelectRect(int tile_size, float scale) { - const ImGuiIO &io = ImGui::GetIO(); - static ImVec2 drag_start_pos; - static bool dragging = false; - - if (ImGui::IsMouseClicked(ImGuiMouseButton_Right)) { - // Start dragging and snap the start position to the nearest grid point - drag_start_pos = { - std::floor(io.MousePos.x / (tile_size * scale)) * tile_size * scale, - std::floor(io.MousePos.y / (tile_size * scale)) * tile_size * scale}; - dragging = true; - } - if (dragging) { - ImVec2 current_pos = io.MousePos; - // Snap current position to the nearest grid point - ImVec2 snapped_current_pos{ - std::floor(current_pos.x / (tile_size * scale)) * tile_size * scale, - std::floor(current_pos.y / (tile_size * scale)) * tile_size * scale}; - - // Calculate rect_min and rect_max considering the drag direction - ImVec2 rect_min = ImVec2(std::min(drag_start_pos.x, snapped_current_pos.x), - std::min(drag_start_pos.y, snapped_current_pos.y)); - ImVec2 rect_max = ImVec2( - std::max(drag_start_pos.x, snapped_current_pos.x) + tile_size * scale, - std::max(drag_start_pos.y, snapped_current_pos.y) + tile_size * scale); - - if (ImGui::IsMouseDragging(ImGuiMouseButton_Right)) { - draw_list_->AddRect(rect_min, rect_max, kRectangleBorder); - } - - if (!ImGui::IsMouseDown(ImGuiMouseButton_Right)) { - dragging = false; - ImVec2 scaled_rect_min = - ImVec2(drag_start_pos.x / scale, drag_start_pos.y / scale); - ImVec2 scaled_rect_max = ImVec2(rect_max.x / scale, rect_max.y / scale); - - // Calculate the bounds of the rectangle in terms of 16x16 tile indices - constexpr int tile16_size = 16; - int start_x = scaled_rect_min.x / tile16_size; - int start_y = scaled_rect_min.y / tile16_size; - int end_x = scaled_rect_max.x / tile16_size; - int end_y = scaled_rect_max.y / tile16_size; - - // Loop through the tiles in the rectangle and store their positions - selected_tiles_.clear(); - for (int y = start_y; y < end_y; ++y) { - for (int x = start_x; x < end_x; ++x) { - selected_tiles_.push_back(ImVec2(x * tile16_size, y * tile16_size)); - } - } - - // Clear and add the calculated rectangle points - points_.clear(); - points_.push_back(scaled_rect_min); - points_.push_back(scaled_rect_max); - } - } -} - void Canvas::DrawSelectRectTile16(int current_map) { const ImGuiIO &io = ImGui::GetIO(); const ImVec2 origin(canvas_p0_.x + scrolling_.x, canvas_p0_.y + scrolling_.y); @@ -497,46 +403,167 @@ void Canvas::DrawSelectRectTile16(int current_map) { } } +namespace { +ImVec2 AlignPosToGrid(ImVec2 pos, float scale) { + return ImVec2(std::floor((double)pos.x / scale) * scale, + std::floor((double)pos.y / scale) * scale); +} +} // namespace + +void Canvas::DrawSelectRect(int current_map, int tile_size, float scale) { + const ImGuiIO &io = ImGui::GetIO(); + const ImVec2 origin(canvas_p0_.x + scrolling_.x, canvas_p0_.y + scrolling_.y); + const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y); + static ImVec2 drag_start_pos; + const float scaled_size = tile_size * scale; + static bool dragging = false; + constexpr int small_map_size = 0x200; + int superY = current_map / 8; + int superX = current_map % 8; + + // Handle right click for single tile selection + if (ImGui::IsMouseClicked(ImGuiMouseButton_Right)) { + ImVec2 painter_pos = AlignPosToGrid(mouse_pos, scaled_size); + int painter_x = painter_pos.x; + int painter_y = painter_pos.y; + + auto tile16_x = (painter_x % small_map_size) / (small_map_size / 0x20); + auto tile16_y = (painter_y % small_map_size) / (small_map_size / 0x20); + + int index_x = superX * 0x20 + tile16_x; + int index_y = superY * 0x20 + tile16_y; + selected_tile_pos_ = ImVec2(index_x, index_y); + selected_points_.clear(); + select_rect_active_ = false; + + // Start drag position for rectangle selection + drag_start_pos = {std::floor(mouse_pos.x / scaled_size) * scaled_size, + std::floor(mouse_pos.y / scaled_size) * scaled_size}; + } + + // Calculate the rectangle's top-left and bottom-right corners + ImVec2 drag_end_pos = AlignPosToGrid(mouse_pos, scaled_size); + if (ImGui::IsMouseDragging(ImGuiMouseButton_Right)) { + auto start = ImVec2(canvas_p0_.x + drag_start_pos.x, + canvas_p0_.y + drag_start_pos.y); + auto end = ImVec2(canvas_p0_.x + drag_end_pos.x + tile_size, + canvas_p0_.y + drag_end_pos.y + tile_size); + draw_list_->AddRect(start, end, kRectangleBorder); + dragging = true; + } + + if (dragging) { + // Release dragging mode + if (!ImGui::IsMouseDown(ImGuiMouseButton_Right)) { + 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; + + // 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; + + // 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 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)); + } + } + // 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; + } + } +} + void Canvas::DrawBitmapGroup(std::vector &group, std::vector &tile16_individual_, int tile_size, float scale) { - if (points_.size() != 2) { - // Handle error: points_ should contain exactly two points + if (selected_points_.size() != 2) { + // points_ should contain exactly two points + return; + } + if (group.empty()) { + // group should not be empty return; } // Top-left and bottom-right corners of the rectangle - ImVec2 rect_top_left = points_[0]; - ImVec2 rect_bottom_right = points_[1]; + ImVec2 rect_top_left = selected_points_[0]; + ImVec2 rect_bottom_right = selected_points_[1]; // Calculate the start and end tiles in the grid - int start_tile_x = static_cast(rect_top_left.x / (tile_size * scale)); - int start_tile_y = static_cast(rect_top_left.y / (tile_size * scale)); - int end_tile_x = static_cast(rect_bottom_right.x / (tile_size * scale)); - int end_tile_y = static_cast(rect_bottom_right.y / (tile_size * scale)); + int start_tile_x = + static_cast(std::floor(rect_top_left.x / (tile_size * scale))); + int start_tile_y = + static_cast(std::floor(rect_top_left.y / (tile_size * scale))); + int end_tile_x = + static_cast(std::floor(rect_bottom_right.x / (tile_size * scale))); + int end_tile_y = + static_cast(std::floor(rect_bottom_right.y / (tile_size * scale))); + + if (start_tile_x > end_tile_x) std::swap(start_tile_x, end_tile_x); + if (start_tile_y > end_tile_y) std::swap(start_tile_y, end_tile_y); // Calculate the size of the rectangle in 16x16 grid form - int rect_width = (end_tile_x - start_tile_x + 1) * tile_size; - int rect_height = (end_tile_y - start_tile_y + 1) * tile_size; + int rect_width = (end_tile_x - start_tile_x) * tile_size; + int rect_height = (end_tile_y - start_tile_y) * tile_size; - const int tiles_per_row = rect_width / tile_size; + int tiles_per_row = rect_width / tile_size; + int tiles_per_col = rect_height / tile_size; - for (int i = 0; i < group.size(); ++i) { - int tile_id = group[i]; + int i = 0; + for (int y = 0; y < tiles_per_col + 1; ++y) { + for (int x = 0; x < tiles_per_row + 1; ++x) { + int tile_id = group[i]; - // Check if tile_id is within the range of tile16_individual_ - if (tile_id >= 0 && tile_id < tile16_individual_.size()) { - int x = i % tiles_per_row; - int y = i / tiles_per_row; + // Check if tile_id is within the range of tile16_individual_ + if (tile_id >= 0 && tile_id < tile16_individual_.size()) { + // Calculate the position of the tile within the rectangle + int tile_pos_x = (x + start_tile_x) * tile_size * scale; + int tile_pos_y = (y + start_tile_y) * tile_size * scale; - // Calculate the position of the tile within the rectangle - int tile_pos_x = x * tile_size * scale + start_tile_x * tile_size * scale; - int tile_pos_y = y * tile_size * scale + start_tile_y * tile_size * scale; - - // Draw the tile bitmap at the calculated position - DrawBitmap(tile16_individual_[tile_id], tile_pos_x, tile_pos_y, scale); + // Draw the tile bitmap at the calculated position + DrawBitmap(tile16_individual_[tile_id], tile_pos_x, tile_pos_y, scale, + 150.0f); + i++; + } } } + + const ImGuiIO &io = ImGui::GetIO(); + const ImVec2 origin(canvas_p0_.x + scrolling_.x, canvas_p0_.y + scrolling_.y); + const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y); + auto new_start_pos = AlignPosToGrid(mouse_pos, tile_size * scale); + auto new_end_pos = + ImVec2(new_start_pos.x + rect_width, new_start_pos.y + rect_height); + selected_points_.clear(); + selected_points_.push_back(new_start_pos); + selected_points_.push_back(new_end_pos); + select_rect_active_ = true; } void Canvas::DrawRect(int x, int y, int w, int h, ImVec4 color) { @@ -645,6 +672,16 @@ void Canvas::DrawOverlay() { IM_COL32(255, 255, 255, 255), 1.0f); } + if (!selected_points_.empty()) { + for (int n = 0; n < selected_points_.size(); n += 2) { + draw_list_->AddRect(ImVec2(origin.x + selected_points_[n].x, + origin.y + selected_points_[n].y), + ImVec2(origin.x + selected_points_[n + 1].x + 0x10, + origin.y + selected_points_[n + 1].y + 0x10), + IM_COL32(255, 255, 255, 255), 1.0f); + } + } + draw_list_->PopClipRect(); } diff --git a/src/app/gui/canvas.h b/src/app/gui/canvas.h index 1ec6921a..909a5949 100644 --- a/src/app/gui/canvas.h +++ b/src/app/gui/canvas.h @@ -77,21 +77,15 @@ class Canvas { // in the canvas window. Represented and split apart into a grid of tiles. bool DrawTileSelector(int size); - bool HandleTileEdits(Canvas& blockset_canvas, - std::vector& source_blockset, - int& current_tile, float scale = 1.0f, - int tile_painter_size = 16, int tiles_per_row = 8); - // Draws the contents of the Bitmap image to the Canvas void DrawBitmap(const Bitmap& bitmap, int border_offset = 0, bool ready = true); void DrawBitmap(const Bitmap& bitmap, int border_offset, float scale); void DrawBitmap(const Bitmap& bitmap, int x_offset = 0, int y_offset = 0, - float scale = 1.0f); - + float scale = 1.0f, int alpha = 255); void DrawBitmapTable(const BitmapTable& gfx_bin); - void DrawBitmapGroup(std::vector &group, + void DrawBitmapGroup(std::vector& group, std::vector& tile16_individual_, int tile_size, float scale = 1.0f); @@ -99,7 +93,8 @@ class Canvas { void DrawOutlineWithColor(int x, int y, int w, int h, ImVec4 color); void DrawOutlineWithColor(int x, int y, int w, int h, uint32_t color); - void DrawSelectRect(int tile_size, float scale = 1.0f); + void DrawSelectRect(int current_map, int tile_size = 0x10, + float scale = 1.0f); void DrawSelectRectTile16(int current_map); void DrawRect(int x, int y, int w, int h, ImVec4 color); @@ -113,8 +108,8 @@ class Canvas { custom_canvas_size_ = true; } bool IsMouseHovering() const { return is_hovered_; } - void ZoomIn() { global_scale_ += 0.1f; } - void ZoomOut() { global_scale_ -= 0.1f; } + void ZoomIn() { global_scale_ += 0.25f; } + void ZoomOut() { global_scale_ -= 0.25f; } auto points() const { return points_; } auto mutable_points() { return &points_; } @@ -130,6 +125,7 @@ class Canvas { auto custom_step() const { return custom_step_; } auto width() const { return canvas_sz_.x; } auto height() const { return canvas_sz_.y; } + auto set_draggable(bool value) { draggable_ = value; } auto labels(int i) { if (i >= labels_.size()) { @@ -158,11 +154,15 @@ class Canvas { 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; } auto selected_tiles() const { return selected_tiles_; } auto mutable_selected_tiles() { return &selected_tiles_; } + auto selected_tile_pos() const { return selected_tile_pos_; } + auto set_selected_tile_pos(ImVec2 pos) { selected_tile_pos_ = pos; } + bool select_rect_active() const { return select_rect_active_; } + auto selected_points() const { return selected_points_; } + private: bool draggable_ = false; bool enable_grid_ = true; @@ -188,6 +188,9 @@ class Canvas { ImVec2 mouse_pos_in_canvas_; ImVec2 drawn_tile_pos_; + bool select_rect_active_ = false; + ImVec2 selected_tile_pos_ = ImVec2(-1, -1); + ImVector selected_points_; std::vector selected_tiles_; };