From ee5e650becf26f1070c50370bfd80f521a6aaf1f Mon Sep 17 00:00:00 2001 From: scawful Date: Tue, 30 Jan 2024 23:55:50 -0500 Subject: [PATCH] Tile16 select rectangle, refresh tile16 blockset --- src/app/editor/overworld_editor.cc | 162 +++++++++++++++++++++++++---- src/app/editor/overworld_editor.h | 3 + 2 files changed, 142 insertions(+), 23 deletions(-) diff --git a/src/app/editor/overworld_editor.cc b/src/app/editor/overworld_editor.cc index f4a573a1..4bf248ca 100644 --- a/src/app/editor/overworld_editor.cc +++ b/src/app/editor/overworld_editor.cc @@ -551,38 +551,96 @@ void OverworldEditor::RenderUpdatedMapBitmap(const ImVec2 &click_position, } void OverworldEditor::CheckForOverworldEdits() { - // User has selected a tile they want to draw from the blockset. - if (!blockset_canvas_.points().empty() && - current_mode == EditingMode::DRAW_TILE) { + if (current_mode == EditingMode::DRAW_TILE) { CheckForSelectRectangle(); - if (ow_map_canvas_.DrawTilePainter(tile16_individual_[current_tile16_], - 16)) { - DrawOverworldEdits(); + // User has selected a tile they want to draw from the blockset. + if (!blockset_canvas_.points().empty() && + !ow_map_canvas_.select_rect_active()) { + // Left click is pressed + if (ow_map_canvas_.DrawTilePainter(tile16_individual_[current_tile16_], + 16)) { + DrawOverworldEdits(); + } + } + + if (ow_map_canvas_.select_rect_active()) { + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) || + ImGui::IsMouseDragging(ImGuiMouseButton_Left)) { + auto &selected_world = + (current_world_ == 0) ? overworld_.mutable_map_tiles()->light_world + : (current_world_ == 1) + ? overworld_.mutable_map_tiles()->dark_world + : overworld_.mutable_map_tiles()->special_world; + // new_start_pos and new_end_pos + auto start = ow_map_canvas_.selected_points()[0]; + auto end = ow_map_canvas_.selected_points()[1]; + + // Calculate the bounds of the rectangle in terms of 16x16 tile indices + constexpr int tile16_size = 16; + int start_x = std::floor(start.x / tile16_size) * tile16_size; + int start_y = std::floor(start.y / tile16_size) * tile16_size; + int end_x = std::floor(end.x / tile16_size) * tile16_size; + int end_y = std::floor(end.y / tile16_size) * tile16_size; + + if (start_x > end_x) std::swap(start_x, end_x); + if (start_y > end_y) std::swap(start_y, end_y); + + constexpr int local_map_size = 512; // Size of each local map + // Number of tiles per local map (since each tile is 16x16) + constexpr int tiles_per_local_map = local_map_size / 16; + + for (int y = start_y, i = 0; y <= end_y; y += tile16_size) { + for (int x = start_x; x <= end_x; x += tile16_size, ++i) { + // Determine which local map (512x512) the tile is in + int local_map_x = x / local_map_size; + int local_map_y = y / local_map_size; + + // Calculate the tile's position within its local map + int tile16_x = (x % local_map_size) / tile16_size; + int tile16_y = (y % local_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; + int tile16_id = overworld_.GetTileFromPosition( + ow_map_canvas_.selected_tiles()[i]); + selected_world[index_x][index_y] = tile16_id; + } + } + + RefreshOverworldMap(); + } } } } void OverworldEditor::CheckForSelectRectangle() { - ow_map_canvas_.DrawSelectRectTile16(current_map_); + ow_map_canvas_.DrawSelectRect(current_map_); + + // Single tile case + if (ow_map_canvas_.selected_tile_pos().x != -1) { + current_tile16_ = + overworld_.GetTileFromPosition(ow_map_canvas_.selected_tile_pos()); + ow_map_canvas_.set_selected_tile_pos(ImVec2(-1, -1)); + } static std::vector tile16_ids; - if (ow_map_canvas_.selected_tiles().size() != 0) { + if (ow_map_canvas_.select_rect_active()) { // Get the tile16 IDs from the selected tile ID positions - // if (tile16_ids.size() != 0) { - // tile16_ids.clear(); - // } - // for (auto &each : ow_map_canvas_.selected_tiles()) { - // tile16_ids.push_back(overworld_.GetTile16Id(each)); - // } - if (ow_map_canvas_.selected_tiles().size() == 1) { - current_tile16_ = - overworld_.GetTile16Id(ow_map_canvas_.selected_tiles().at(0)); + if (tile16_ids.size() != 0) { + tile16_ids.clear(); } - ow_map_canvas_.mutable_selected_tiles()->clear(); + + if (ow_map_canvas_.selected_tiles().size() > 0) { + for (auto &each : ow_map_canvas_.selected_tiles()) { + tile16_ids.push_back(overworld_.GetTileFromPosition(each)); + } + } + // ow_map_canvas_.mutable_selected_tiles()->clear(); } // Create a composite image of all the tile16s selected - // ow_map_canvas_.DrawBitmapGroup(tile16_ids, tile16_individual_, 0x10); + ow_map_canvas_.DrawBitmapGroup(tile16_ids, tile16_individual_, 0x10); } void OverworldEditor::CheckForCurrentMap() { @@ -625,7 +683,10 @@ void OverworldEditor::CheckForCurrentMap() { small_map_size); } - if (maps_bmp_[current_map_].modified()) { + if (maps_bmp_[current_map_].modified() || + ImGui::IsMouseClicked(ImGuiMouseButton_Right)) { + RefreshOverworldMap(); + RefreshTile16Blockset(); rom()->UpdateBitmap(&maps_bmp_[current_map_]); maps_bmp_[current_map_].set_modified(false); } @@ -654,8 +715,8 @@ void OverworldEditor::DrawOverworldCanvas() { ow_map_canvas_.scrolling()); DrawOverworldItems(); DrawOverworldSprites(); - if (ImGui::IsItemHovered()) CheckForCurrentMap(); CheckForOverworldEdits(); + if (ImGui::IsItemHovered()) CheckForCurrentMap(); } ow_map_canvas_.DrawGrid(); ow_map_canvas_.DrawOverlay(); @@ -718,7 +779,7 @@ void OverworldEditor::DrawAreaGraphics() { gui::EndPadding(); current_gfx_canvas_.DrawContextMenu(); if (current_graphics_set_.count(current_map_) == 0) { - overworld_.SetCurrentMap(current_map_); + overworld_.set_current_map(current_map_); palette_ = overworld_.AreaPalette(); gfx::Bitmap bmp; gui::BuildAndRenderBitmapPipeline( @@ -1535,7 +1596,7 @@ absl::Status OverworldEditor::LoadGraphics() { // Render the overworld maps loaded from the ROM. for (int i = 0; i < zelda3::kNumOverworldMaps; ++i) { - overworld_.SetCurrentMap(i); + overworld_.set_current_map(i); auto palette = overworld_.AreaPalette(); gui::BuildAndRenderBitmapPipeline(0x200, 0x200, 0x200, overworld_.BitmapData(), *rom(), @@ -1549,6 +1610,61 @@ absl::Status OverworldEditor::LoadGraphics() { return absl::OkStatus(); } +void OverworldEditor::RefreshTile16Blockset() { + if (current_blockset_ == + overworld_.overworld_map(current_map_)->area_graphics()) { + return; + } + current_blockset_ = overworld_.overworld_map(current_map_)->area_graphics(); + + overworld_.set_current_map(current_map_); + palette_ = overworld_.AreaPalette(); + // Create the tile16 blockset image + gui::BuildAndRenderBitmapPipeline(0x80, 0x2000, 0x08, + overworld_.Tile16Blockset(), *rom(), + tile16_blockset_bmp_, palette_); + + // Copy the tile16 data into individual tiles. + auto tile16_data = overworld_.Tile16Blockset(); + + std::vector> futures; + // Loop through the tiles and copy their pixel data into separate vectors + for (int i = 0; i < 4096; i++) { + futures.push_back(std::async( + std::launch::async, + [&](int index) { + // Create a new vector for the pixel data of the current tile + Bytes tile_data(16 * 16, 0x00); // More efficient initialization + + // Copy the pixel data for the current tile into the vector + for (int ty = 0; ty < 16; ty++) { + for (int tx = 0; tx < 16; tx++) { + int position = tx + (ty * 0x10); + uchar value = + tile16_data[(index % 8 * 16) + (index / 8 * 16 * 0x80) + + (ty * 0x80) + tx]; + tile_data[position] = value; + } + } + + // Add the vector for the current tile to the vector of tile pixel + // data + tile16_individual_[index].set_data(tile_data); + }, + i)); + } + + for (auto &future : futures) { + future.get(); + } + + // Render the bitmaps of each tile. + for (int id = 0; id < 4096; id++) { + tile16_individual_[id].ApplyPalette(palette_); + rom()->UpdateBitmap(&tile16_individual_[id]); + } +} + absl::Status OverworldEditor::LoadSpriteGraphics() { // Render the sprites for each Overworld map for (int i = 0; i < 3; i++) diff --git a/src/app/editor/overworld_editor.h b/src/app/editor/overworld_editor.h index 564bd348..d359c098 100644 --- a/src/app/editor/overworld_editor.h +++ b/src/app/editor/overworld_editor.h @@ -105,6 +105,7 @@ class OverworldEditor : public Editor, void RefreshOverworldMap(); void RefreshMapPalette(); void RefreshMapProperties(); + void RefreshTile16Blockset(); void DrawOverworldEntrances(ImVec2 canvas_p, ImVec2 scrolling, bool holes = false); @@ -162,6 +163,8 @@ class OverworldEditor : public Editor, int current_tile16_ = 0; int selected_tile_ = 0; + int current_blockset_ = 0; + int selected_entrance_ = 0; int selected_usage_map_ = 0xFFFF;