diff --git a/src/app/editor/editor.cmake b/src/app/editor/editor.cmake index 4e7a5f95..48913e4b 100644 --- a/src/app/editor/editor.cmake +++ b/src/app/editor/editor.cmake @@ -11,7 +11,7 @@ set( app/editor/graphics/screen_editor.cc app/editor/graphics/graphics_editor.cc app/editor/graphics/palette_editor.cc - app/editor/graphics/tile16_editor.cc + app/editor/overworld/tile16_editor.cc app/editor/graphics/gfx_group_editor.cc app/editor/overworld/entity.cc app/editor/system/settings_editor.cc diff --git a/src/app/editor/overworld/overworld_editor.cc b/src/app/editor/overworld/overworld_editor.cc index 2b0bdc4c..a00fab36 100644 --- a/src/app/editor/overworld/overworld_editor.cc +++ b/src/app/editor/overworld/overworld_editor.cc @@ -14,6 +14,7 @@ #include "app/editor/overworld/entity.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_palette.h" +#include "app/gfx/tilemap.h" #include "app/gui/canvas.h" #include "app/gui/icons.h" #include "app/gui/input.h" @@ -427,8 +428,8 @@ void OverworldEditor::DrawOverworldEdits() { } // Render the updated map bitmap. - RenderUpdatedMapBitmap(mouse_position, - tile16_individual_[current_tile16_].vector()); + RenderUpdatedMapBitmap( + mouse_position, gfx::GetTilemapData(tile16_blockset_, current_tile16_)); // Calculate the correct superX and superY values int superY = current_map_ / 8; @@ -484,8 +485,7 @@ void OverworldEditor::CheckForOverworldEdits() { if (!blockset_canvas_.points().empty() && !ow_map_canvas_.select_rect_active()) { // Left click is pressed - if (ow_map_canvas_.DrawTilePainter(tile16_individual_[current_tile16_], - kTile16Size)) { + if (ow_map_canvas_.DrawTilemapPainter(tile16_blockset_, current_tile16_)) { DrawOverworldEdits(); } } @@ -563,7 +563,7 @@ void OverworldEditor::CheckForSelectRectangle() { } } // 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_blockset_, 0x10); } absl::Status OverworldEditor::CheckForCurrentMap() { @@ -685,7 +685,7 @@ absl::Status OverworldEditor::DrawTile16Selector() { gui::EndNoPadding(); { blockset_canvas_.DrawContextMenu(); - blockset_canvas_.DrawBitmap(tile16_blockset_bmp_, /*border_offset=*/2, + blockset_canvas_.DrawBitmap(tile16_blockset_.atlas, /*border_offset=*/2, map_blockset_loaded_); if (blockset_canvas_.DrawTileSelector(32.0f)) { @@ -1050,27 +1050,11 @@ absl::Status OverworldEditor::LoadGraphics() { // Copy the tile16 data into individual tiles. auto tile16_blockset_data = overworld_.tile16_blockset_data(); - util::logf("Loading overworld tile16 graphics."); - // Loop through the tiles and copy their pixel data into separate vectors - for (unsigned int i = 0; i < zelda3::kNumTile16Individual; i++) { - std::vector tile16_data(kTile16Size * kTile16Size); - tile16_individual_[i].Create(kTile16Size, kTile16Size, 0x08, tile16_data); - // 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_blockset_data[(i % 8 * kTile16Size) + - (i / 8 * kTile16Size * 0x80) + - (ty * 0x80) + tx]; - tile16_individual_[i].mutable_data()[position] = value; - } - } - - tile16_individual_[i].SetPalette(palette_); - Renderer::GetInstance().RenderBitmap(&tile16_individual_[i]); - } + tile16_blockset_ = + gfx::CreateTilemap(tile16_blockset_data, 0x80, 0x2000, kTile16Size, + zelda3::kNumTile16Individual, palette_); util::logf("Loading overworld maps."); // Render the overworld maps loaded from the ROM. @@ -1216,46 +1200,11 @@ absl::Status OverworldEditor::RefreshTile16Blockset() { overworld_.set_current_map(current_map_); palette_ = overworld_.current_area_palette(); - // Create the tile16 blockset image - Renderer::GetInstance().UpdateBitmap(&tile16_blockset_bmp_); - tile16_blockset_bmp_.SetPalette(palette_); - // Copy the tile16 data into individual tiles. const auto tile16_data = overworld_.tile16_blockset_data(); - // Loop through the tiles and copy their pixel data into separate vectors - std::vector> futures; - for (unsigned int i = 0; i < zelda3::kNumTile16Individual; i++) { - futures.push_back(std::async( - std::launch::async, - [&](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++) { - int position = tx + (ty * 0x10); - uint8_t value = - tile16_data[(index % 8 * 16) + (index / 8 * 16 * 0x80) + - (ty * 0x80) + tx]; - tile_data[position] = value; - } - } - tile16_individual_[index].set_data(tile_data); - tile16_individual_[index].SetPalette(palette_); - return absl::OkStatus(); - }, - i)); - } - - for (auto &future : futures) { - future.wait(); - RETURN_IF_ERROR(future.get()); - } - - // Render the bitmaps of each tile. - for (unsigned int id = 0; id < zelda3::kNumTile16Individual; id++) { - Renderer::GetInstance().UpdateBitmap(&tile16_individual_[id]); - } - + gfx::UpdateTilemap(tile16_blockset_, tile16_data); + tile16_blockset_.atlas.SetPalette(palette_); return absl::OkStatus(); } @@ -1496,9 +1445,6 @@ void OverworldEditor::DrawDebugWindow() { absl::Status OverworldEditor::Clear() { overworld_.Destroy(); current_graphics_set_.clear(); - for (auto &bmp : tile16_individual_) { - bmp.Clear(); - } for (auto &bmp : maps_bmp_) { bmp.Clear(); } @@ -1514,9 +1460,6 @@ absl::Status OverworldEditor::Clear() { void OverworldEditor::CleanupUnusedTextures(uint64_t current_time, uint64_t timeout) { - for (auto &bmp : tile16_individual_) { - bmp.CleanupUnusedTexture(current_time, timeout); - } for (auto &bmp : maps_bmp_) { bmp.CleanupUnusedTexture(current_time, timeout); } diff --git a/src/app/editor/overworld/overworld_editor.h b/src/app/editor/overworld/overworld_editor.h index 596567d6..529a9ca1 100644 --- a/src/app/editor/overworld/overworld_editor.h +++ b/src/app/editor/overworld/overworld_editor.h @@ -5,9 +5,10 @@ #include "app/editor/editor.h" #include "app/editor/graphics/gfx_group_editor.h" #include "app/editor/graphics/palette_editor.h" -#include "app/editor/graphics/tile16_editor.h" +#include "app/editor/overworld/tile16_editor.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_palette.h" +#include "app/gfx/tilemap.h" #include "app/gui/canvas.h" #include "app/gui/input.h" #include "app/gui/zeml.h" @@ -74,7 +75,9 @@ constexpr absl::string_view kOWMapTable = "#MapSettingsTable"; */ class OverworldEditor : public Editor, public gfx::GfxContext { public: - explicit OverworldEditor(Rom* rom) : rom_(rom) { type_ = EditorType::kOverworld; } + explicit OverworldEditor(Rom* rom) : rom_(rom) { + type_ = EditorType::kOverworld; + } void Initialize() override; absl::Status Load() override; @@ -89,7 +92,7 @@ class OverworldEditor : public Editor, public gfx::GfxContext { absl::Status Clear() override; void CleanupUnusedTextures(uint64_t current_time, uint64_t timeout) override; - + int jump_to_tab() { return jump_to_tab_; } int jump_to_tab_ = -1; @@ -213,14 +216,14 @@ class OverworldEditor : public Editor, public gfx::GfxContext { bool is_dragging_entity_ = false; std::vector selected_tile_data_; - std::array tile16_individual_; + gfx::Tilemap tile16_blockset_; std::vector> tile8_individual_data_; std::vector tile8_individual_; Rom* rom_; - Tile16Editor tile16_editor_{&tile16_individual_}; + Tile16Editor tile16_editor_{&tile16_blockset_}; GfxGroupEditor gfx_group_editor_; PaletteEditor palette_editor_; diff --git a/src/app/editor/graphics/tile16_editor.cc b/src/app/editor/overworld/tile16_editor.cc similarity index 97% rename from src/app/editor/graphics/tile16_editor.cc rename to src/app/editor/overworld/tile16_editor.cc index 78682bb1..ef3844ce 100644 --- a/src/app/editor/graphics/tile16_editor.cc +++ b/src/app/editor/overworld/tile16_editor.cc @@ -187,10 +187,11 @@ absl::Status Tile16Editor::UpdateBlockset() { if (notify_tile16.modified()) { current_tile16_ = notify_tile16.get(); - current_tile16_bmp_ = (*tile16_individual_)[notify_tile16]; + gfx::RenderTile(*tile16_blockset_, current_tile16_); + current_tile16_bmp_ = tile16_blockset_->tile_bitmaps[notify_tile16]; auto ow_main_pal_group = rom()->palette_group().overworld_main; current_tile16_bmp_.SetPalette(ow_main_pal_group[current_palette_]); - Renderer::GetInstance().RenderBitmap(¤t_tile16_bmp_); + Renderer::GetInstance().UpdateBitmap(¤t_tile16_bmp_); } } @@ -487,10 +488,11 @@ absl::Status Tile16Editor::LoadTile8() { absl::Status Tile16Editor::SetCurrentTile(int id) { current_tile16_ = id; - current_tile16_bmp_ = (*tile16_individual_)[id]; + gfx::RenderTile(*tile16_blockset_, current_tile16_); + current_tile16_bmp_ = tile16_blockset_->tile_bitmaps[current_tile16_]; auto ow_main_pal_group = rom()->palette_group().overworld_main; current_tile16_bmp_.SetPalette(ow_main_pal_group[current_palette_]); - Renderer::GetInstance().RenderBitmap(¤t_tile16_bmp_); + Renderer::GetInstance().UpdateBitmap(¤t_tile16_bmp_); return absl::OkStatus(); } @@ -561,8 +563,11 @@ absl::Status Tile16Editor::CopyTile16ToClipboard(int tile_id) { } // Create a copy of the tile16 bitmap - clipboard_tile16_.Create(16, 16, 8, (*tile16_individual_)[tile_id].vector()); - clipboard_tile16_.SetPalette((*tile16_individual_)[tile_id].palette()); + gfx::RenderTile(*tile16_blockset_, tile_id); + clipboard_tile16_.Create(16, 16, 8, + tile16_blockset_->tile_bitmaps[tile_id].vector()); + clipboard_tile16_.SetPalette( + tile16_blockset_->tile_bitmaps[tile_id].palette()); core::Renderer::GetInstance().RenderBitmap(&clipboard_tile16_); clipboard_has_data_ = true; diff --git a/src/app/editor/graphics/tile16_editor.h b/src/app/editor/overworld/tile16_editor.h similarity index 93% rename from src/app/editor/graphics/tile16_editor.h rename to src/app/editor/overworld/tile16_editor.h index b789767e..abd7bbe9 100644 --- a/src/app/editor/graphics/tile16_editor.h +++ b/src/app/editor/overworld/tile16_editor.h @@ -24,9 +24,7 @@ namespace editor { */ class Tile16Editor : public gfx::GfxContext, public SharedRom { public: - Tile16Editor( - std::array *tile16_individual) - : tile16_individual_(tile16_individual) {} + Tile16Editor(gfx::Tilemap *tile16_blockset) : tile16_blockset_(tile16_blockset) {} absl::Status Initialize(const gfx::Bitmap &tile16_blockset_bmp, const gfx::Bitmap ¤t_gfx_bmp, std::array &all_tiles_types); @@ -102,8 +100,7 @@ class Tile16Editor : public gfx::GfxContext, public SharedRom { gui::Table tile_edit_table_{"##TileEditTable", 3, ImGuiTableFlags_Borders}; - std::array *tile16_individual_ = - nullptr; + gfx::Tilemap *tile16_blockset_ = nullptr; std::vector current_gfx_individual_; PaletteEditor palette_editor_; diff --git a/src/app/gui/canvas.cc b/src/app/gui/canvas.cc index ce0d1725..b51226d9 100644 --- a/src/app/gui/canvas.cc +++ b/src/app/gui/canvas.cc @@ -10,7 +10,6 @@ #include "app/gui/style.h" #include "app/rom.h" #include "imgui/imgui.h" -#include "imgui/imgui_internal.h" #include "imgui_memory_editor.h" namespace yaze { @@ -274,6 +273,55 @@ bool Canvas::DrawTilePainter(const Bitmap &bitmap, int size, float scale) { return false; } +bool Canvas::DrawTilemapPainter(gfx::Tilemap &tilemap, int current_tile) { + const ImGuiIO &io = GetIO(); + const bool is_hovered = IsItemHovered(); + is_hovered_ = is_hovered; + 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); + const auto scaled_size = tilemap.tile_size.x * global_scale_; + + if (!is_hovered) { + points_.clear(); + return false; + } + + if (!points_.empty()) { + points_.clear(); + } + + ImVec2 paint_pos = AlignPosToGrid(mouse_pos, scaled_size); + mouse_pos_in_canvas_ = paint_pos; + + points_.push_back(paint_pos); + points_.push_back( + ImVec2(paint_pos.x + scaled_size, paint_pos.y + scaled_size)); + + if (tilemap.tile_bitmaps.find(current_tile) == tilemap.tile_bitmaps.end()) { + tilemap.tile_bitmaps[current_tile] = gfx::Bitmap( + tilemap.tile_size.x, tilemap.tile_size.y, 8, + gfx::GetTilemapData(tilemap, current_tile), tilemap.atlas.palette()); + auto bitmap_ptr = &tilemap.tile_bitmaps[current_tile]; + Renderer::GetInstance().RenderBitmap(bitmap_ptr); + } + + draw_list_->AddImage( + (ImTextureID)(intptr_t)tilemap.tile_bitmaps[current_tile].texture(), + ImVec2(origin.x + paint_pos.x, origin.y + paint_pos.y), + 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)) { + drawn_tile_pos_ = paint_pos; + return true; + } + + return false; +} + bool Canvas::DrawSolidTilePainter(const ImVec4 &color, int tile_size) { const ImGuiIO &io = GetIO(); const bool is_hovered = IsItemHovered(); @@ -541,8 +589,7 @@ void Canvas::DrawOutlineWithColor(int x, int y, int w, int h, uint32_t color) { draw_list_->AddRect(origin, size, color); } -void Canvas::DrawBitmapGroup(std::vector &group, - std::array &tile16_individual_, +void Canvas::DrawBitmapGroup(std::vector &group, gfx::Tilemap &tilemap, int tile_size, float scale) { if (selected_points_.size() != 2) { // points_ should contain exactly two points @@ -583,13 +630,16 @@ void Canvas::DrawBitmapGroup(std::vector &group, 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()) { + auto tilemap_size = tilemap.atlas.width() * tilemap.atlas.height() / + tilemap.map_size.x; + if (tile_id >= 0 && tile_id < tilemap_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; // Draw the tile bitmap at the calculated position - DrawBitmap(tile16_individual_[tile_id], tile_pos_x, tile_pos_y, scale, + gfx::RenderTile(tilemap, tile_id); + DrawBitmap(tilemap.tile_bitmaps[tile_id], tile_pos_x, tile_pos_y, scale, 150.0f); i++; } diff --git a/src/app/gui/canvas.h b/src/app/gui/canvas.h index ddcb9802..6b22d61e 100644 --- a/src/app/gui/canvas.h +++ b/src/app/gui/canvas.h @@ -1,6 +1,7 @@ #ifndef YAZE_GUI_CANVAS_H #define YAZE_GUI_CANVAS_H +#include "gfx/tilemap.h" #define IMGUI_DEFINE_MATH_OPERATORS #include @@ -116,9 +117,11 @@ class Canvas : public SharedRom { void DrawBitmapTable(const BitmapTable &gfx_bin); void DrawBitmapGroup(std::vector &group, - std::array &tile16_individual_, + gfx::Tilemap &tilemap, int tile_size, float scale = 1.0f); + bool DrawTilemapPainter(gfx::Tilemap &tilemap, int current_tile); + void DrawOutline(int x, int y, int w, int h); 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);