From a682ea955303d6b4a7fb7051bcff0c1178c142b4 Mon Sep 17 00:00:00 2001 From: scawful Date: Sun, 18 May 2025 16:46:04 -0400 Subject: [PATCH] Port ScreenEditor to use Tilemap, remove Tilesheet class --- src/app/editor/editor_manager.cc | 3 +- src/app/editor/graphics/screen_editor.cc | 292 +++++------------------ src/app/editor/graphics/screen_editor.h | 11 +- src/app/gfx/gfx.cmake | 1 - src/app/gfx/tilesheet.cc | 176 -------------- src/app/gfx/tilesheet.h | 133 ----------- 6 files changed, 63 insertions(+), 553 deletions(-) delete mode 100644 src/app/gfx/tilesheet.cc delete mode 100644 src/app/gfx/tilesheet.h diff --git a/src/app/editor/editor_manager.cc b/src/app/editor/editor_manager.cc index eb35d09b..5f28584a 100644 --- a/src/app/editor/editor_manager.cc +++ b/src/app/editor/editor_manager.cc @@ -567,7 +567,8 @@ absl::Status EditorManager::SaveRom() { } if (core::FeatureFlags::get().kSaveDungeonMaps) { - RETURN_IF_ERROR(current_editor_set_->screen_editor_.SaveDungeonMaps()); + RETURN_IF_ERROR(zelda3::SaveDungeonMaps( + *current_rom_, current_editor_set_->screen_editor_.dungeon_maps_)); } RETURN_IF_ERROR(current_editor_set_->overworld_editor_.Save()); diff --git a/src/app/editor/graphics/screen_editor.cc b/src/app/editor/graphics/screen_editor.cc index 684b6338..aa75d855 100644 --- a/src/app/editor/graphics/screen_editor.cc +++ b/src/app/editor/graphics/screen_editor.cc @@ -11,12 +11,10 @@ #include "app/gfx/arena.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" -#include "app/gfx/tilesheet.h" #include "app/gui/canvas.h" #include "app/gui/color.h" #include "app/gui/icons.h" #include "app/gui/input.h" -#include "app/snes.h" #include "imgui/imgui.h" #include "util/hex.h" #include "util/macro.h" @@ -31,29 +29,30 @@ constexpr uint32_t kRedPen = 0xFF0000FF; void ScreenEditor::Initialize() {} absl::Status ScreenEditor::Load() { - RETURN_IF_ERROR(LoadDungeonMaps()); - RETURN_IF_ERROR(LoadDungeonMapTile16(rom()->graphics_buffer())); + ASSIGN_OR_RETURN(dungeon_maps_, + zelda3::LoadDungeonMaps(*rom(), dungeon_map_labels_)); + RETURN_IF_ERROR(zelda3::LoadDungeonMapTile16( + tile16_blockset_, *rom(), rom()->graphics_buffer(), false)); // TODO: Load roomset gfx based on dungeon ID - sheets_.emplace(0, gfx::Arena::Get().gfx_sheets()[212]); - sheets_.emplace(1, gfx::Arena::Get().gfx_sheets()[213]); - sheets_.emplace(2, gfx::Arena::Get().gfx_sheets()[214]); - sheets_.emplace(3, gfx::Arena::Get().gfx_sheets()[215]); - // int current_tile8 = 0; - // int tile_data_offset = 0; - // for (int i = 0; i < 4; ++i) { - // for (int j = 0; j < 32; j++) { - // std::vector tile_data(64, 0); // 8x8 tile (64 bytes - // int tile_index = current_tile8 + j; - // int x = (j % 8) * 8; - // int y = (j / 8) * 8; - // sheets_[i].Get8x8Tile(tile_index, 0, 0, tile_data, - // tile_data_offset); tile8_individual_.emplace_back(gfx::Bitmap(8, 8, - // 4, tile_data)); tile8_individual_.back().SetPalette( - // *rom()->mutable_dungeon_palette(3)); - // Renderer::Get().RenderBitmap(&tile8_individual_.back()); - // } - // tile_data_offset = 0; - // } + sheets_.try_emplace(0, gfx::Arena::Get().gfx_sheets()[212]); + sheets_.try_emplace(1, gfx::Arena::Get().gfx_sheets()[213]); + sheets_.try_emplace(2, gfx::Arena::Get().gfx_sheets()[214]); + sheets_.try_emplace(3, gfx::Arena::Get().gfx_sheets()[215]); + int current_tile8 = 0; + int tile_data_offset = 0; + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 32; j++) { + std::vector tile_data(64, 0); // 8x8 tile (64 bytes + int tile_index = current_tile8 + j; + int x = (j % 8) * 8; + int y = (j / 8) * 8; + sheets_[i].Get8x8Tile(tile_index, x, y, tile_data, tile_data_offset); + tile8_individual_.emplace_back(gfx::Bitmap(8, 8, 4, tile_data)); + tile8_individual_.back().SetPalette(*rom()->mutable_dungeon_palette(3)); + Renderer::Get().RenderBitmap(&tile8_individual_.back()); + } + tile_data_offset = 0; + } return absl::OkStatus(); } @@ -158,173 +157,6 @@ void ScreenEditor::DrawInventoryToolset() { } } -absl::Status ScreenEditor::LoadDungeonMaps() { - std::vector> current_floor_rooms_d; - std::vector> current_floor_gfx_d; - int total_floors_d; - uint8_t nbr_floor_d; - uint8_t nbr_basement_d; - - for (int d = 0; d < 14; d++) { - current_floor_rooms_d.clear(); - current_floor_gfx_d.clear(); - ASSIGN_OR_RETURN(int ptr, - rom()->ReadWord(zelda3::kDungeonMapRoomsPtr + (d * 2))); - ASSIGN_OR_RETURN(int ptr_gfx, - rom()->ReadWord(zelda3::kDungeonMapGfxPtr + (d * 2))); - ptr |= 0x0A0000; // Add bank to the short ptr - ptr_gfx |= 0x0A0000; // Add bank to the short ptr - int pc_ptr = SnesToPc(ptr); // Contains data for the next 25 rooms - int pc_ptr_gfx = SnesToPc(ptr_gfx); // Contains data for the next 25 rooms - - ASSIGN_OR_RETURN(uint16_t boss_room_d, - rom()->ReadWord(zelda3::kDungeonMapBossRooms + (d * 2))); - - ASSIGN_OR_RETURN(nbr_basement_d, - rom()->ReadByte(zelda3::kDungeonMapFloors + (d * 2))); - nbr_basement_d &= 0x0F; - - ASSIGN_OR_RETURN(nbr_floor_d, - rom()->ReadByte(zelda3::kDungeonMapFloors + (d * 2))); - nbr_floor_d &= 0xF0; - nbr_floor_d = nbr_floor_d >> 4; - - total_floors_d = nbr_basement_d + nbr_floor_d; - - dungeon_map_labels_.emplace_back(); - - // for each floor in the dungeon - for (int i = 0; i < total_floors_d; i++) { - dungeon_map_labels_[d].emplace_back(); - - std::array rdata; - std::array gdata; - - // for each room on the floor - for (int j = 0; j < 25; j++) { - gdata[j] = 0xFF; - rdata[j] = rom()->data()[pc_ptr + j + (i * 25)]; // Set the rooms - - if (rdata[j] == 0x0F) { - gdata[j] = 0xFF; - } else { - gdata[j] = rom()->data()[pc_ptr_gfx++]; - } - - std::string label = util::HexByte(rdata[j]); - dungeon_map_labels_[d][i][j] = label; - } - - current_floor_gfx_d.push_back(gdata); // Add new floor gfx data - current_floor_rooms_d.push_back(rdata); // Add new floor data - } - - dungeon_maps_.emplace_back(boss_room_d, nbr_floor_d, nbr_basement_d, - current_floor_rooms_d, current_floor_gfx_d); - } - - return absl::OkStatus(); -} - -absl::Status ScreenEditor::SaveDungeonMaps() { - for (int d = 0; d < 14; d++) { - int ptr = zelda3::kDungeonMapRoomsPtr + (d * 2); - int ptr_gfx = zelda3::kDungeonMapGfxPtr + (d * 2); - int pc_ptr = SnesToPc(ptr); - int pc_ptr_gfx = SnesToPc(ptr_gfx); - - const int nbr_floors = dungeon_maps_[d].nbr_of_floor; - const int nbr_basements = dungeon_maps_[d].nbr_of_basement; - for (int i = 0; i < nbr_floors + nbr_basements; i++) { - for (int j = 0; j < 25; j++) { - RETURN_IF_ERROR(rom()->WriteByte(pc_ptr + j + (i * 25), - dungeon_maps_[d].floor_rooms[i][j])); - RETURN_IF_ERROR(rom()->WriteByte(pc_ptr_gfx + j + (i * 25), - dungeon_maps_[d].floor_gfx[i][j])); - pc_ptr_gfx++; - } - } - } - - return absl::OkStatus(); -} - -absl::Status ScreenEditor::LoadDungeonMapTile16( - const std::vector &gfx_data, bool bin_mode) { - tile16_blockset_.tile_size = {16, 16}; - tile16_blockset_.map_size = {186, 186}; - tile16_blockset_.atlas.Create(256, 192, 8, gfx_data); - tile16_sheet_.Init(256, 192, gfx::TileType::Tile16); - - for (int i = 0; i < 186; i++) { - int addr = zelda3::kDungeonMapTile16; - if (rom()->data()[zelda3::kDungeonMapExpCheck] != 0xB9) { - addr = zelda3::kDungeonMapTile16Expanded; - } - - ASSIGN_OR_RETURN(auto tl, rom()->ReadWord(addr + (i * 8))); - gfx::TileInfo t1 = gfx::WordToTileInfo(tl); // Top left - - ASSIGN_OR_RETURN(auto tr, rom()->ReadWord(addr + 2 + (i * 8))); - gfx::TileInfo t2 = gfx::WordToTileInfo(tr); // Top right - - ASSIGN_OR_RETURN(auto bl, rom()->ReadWord(addr + 4 + (i * 8))); - gfx::TileInfo t3 = gfx::WordToTileInfo(bl); // Bottom left - - ASSIGN_OR_RETURN(auto br, rom()->ReadWord(addr + 6 + (i * 8))); - gfx::TileInfo t4 = gfx::WordToTileInfo(br); // Bottom right - - int sheet_offset = 212; - if (bin_mode) { - sheet_offset = 0; - } - ComposeTile16(tile16_blockset_, gfx_data, t1, t2, t3, t4, sheet_offset); - tile16_sheet_.ComposeTile16(gfx_data, t1, t2, t3, t4, sheet_offset); - } - - tile16_sheet_.mutable_bitmap()->SetPalette( - *rom()->mutable_dungeon_palette(3)); - tile16_blockset_.atlas.SetPalette(*rom()->mutable_dungeon_palette(3)); - Renderer::Get().RenderBitmap(&tile16_blockset_.atlas); - Renderer::Get().RenderBitmap(&*tile16_sheet_.mutable_bitmap().get()); - - for (int i = 0; i < tile16_sheet_.num_tiles(); ++i) { - auto tile = tile16_sheet_.GetTile16(i); - tile16_individual_[i] = tile; - tile16_individual_[i].SetPalette(*rom()->mutable_dungeon_palette(3)); - Renderer::Get().RenderBitmap(&tile16_individual_[i]); - } - - return absl::OkStatus(); -} - -absl::Status ScreenEditor::SaveDungeonMapTile16() { - for (int i = 0; i < 186; i++) { - int addr = zelda3::kDungeonMapTile16; - if (rom()->data()[zelda3::kDungeonMapExpCheck] != 0xB9) { - addr = zelda3::kDungeonMapTile16Expanded; - } - - gfx::TileInfo t1 = tile16_sheet_.tile_info()[i].tiles[0]; - gfx::TileInfo t2 = tile16_sheet_.tile_info()[i].tiles[1]; - gfx::TileInfo t3 = tile16_sheet_.tile_info()[i].tiles[2]; - gfx::TileInfo t4 = tile16_sheet_.tile_info()[i].tiles[3]; - - auto tl = gfx::TileInfoToWord(t1); - RETURN_IF_ERROR(rom()->WriteWord(addr + (i * 8), tl)); - - auto tr = gfx::TileInfoToWord(t2); - RETURN_IF_ERROR(rom()->WriteWord(addr + 2 + (i * 8), tr)); - - auto bl = gfx::TileInfoToWord(t3); - RETURN_IF_ERROR(rom()->WriteWord(addr + 4 + (i * 8), bl)); - - auto br = gfx::TileInfoToWord(t4); - RETURN_IF_ERROR(rom()->WriteWord(addr + 6 + (i * 8), br)); - } - return absl::OkStatus(); -} - void ScreenEditor::DrawDungeonMapsTabs() { auto ¤t_dungeon = dungeon_maps_[selected_dungeon]; if (ImGui::BeginTabBar("##DungeonMapTabs")) { @@ -344,13 +176,13 @@ void ScreenEditor::DrawDungeonMapsTabs() { screen_canvas_.DrawTileSelector(64.f); auto boss_room = current_dungeon.boss_room; - for (int j = 0; j < 25; j++) { + for (int j = 0; j < zelda3::kNumRooms; j++) { if (current_dungeon.floor_rooms[floor_number][j] != 0x0F) { int tile16_id = current_dungeon.floor_gfx[floor_number][j]; int posX = ((j % 5) * 32); int posY = ((j / 5) * 32); - gfx::RenderTile(tile16_blockset_, tile16_id); + gfx::RenderTile16(tile16_blockset_, tile16_id); screen_canvas_.DrawBitmap(tile16_blockset_.tile_bitmaps[tile16_id], (posX * 2), (posY * 2), 4.0f); @@ -428,17 +260,19 @@ void ScreenEditor::DrawDungeonMapsRoomGfx() { if (ImGui::BeginChild("##DungeonMapTiles", ImVec2(0, 0), true)) { tilesheet_canvas_.DrawBackground(ImVec2((256 * 2) + 2, (192 * 2) + 4)); tilesheet_canvas_.DrawContextMenu(); - tilesheet_canvas_.DrawTileSelector(32.f); - tilesheet_canvas_.DrawBitmap(*tile16_sheet_.bitmap(), 2, true); + if (tilesheet_canvas_.DrawTileSelector(32.f)) { + selected_tile16_ = tilesheet_canvas_.points().front().x / 32 + + (tilesheet_canvas_.points().front().y / 32) * 16; + gfx::RenderTile16(tile16_blockset_, selected_tile16_); + std::copy(tile16_blockset_.tile_info[selected_tile16_].begin(), + tile16_blockset_.tile_info[selected_tile16_].end(), + current_tile16_info.begin()); + } + tilesheet_canvas_.DrawBitmap(tile16_blockset_.atlas, 1, 1, 2.0f); tilesheet_canvas_.DrawGrid(32.f); tilesheet_canvas_.DrawOverlay(); if (!tilesheet_canvas_.points().empty()) { - selected_tile16_ = tilesheet_canvas_.points().front().x / 32 + - (tilesheet_canvas_.points().front().y / 32) * 16; - current_tile16_info = tile16_sheet_.tile_info().at(selected_tile16_); - - // Draw the selected tile if (!screen_canvas_.points().empty()) { dungeon_maps_[selected_dungeon].floor_gfx[floor_number][selected_room] = selected_tile16_; @@ -454,51 +288,40 @@ void ScreenEditor::DrawDungeonMapsRoomGfx() { // 16)) { // Modify the tile16 based on the selected tile and current_tile16_info // } - current_tile_canvas_.DrawBitmap(tile16_individual_[selected_tile16_], 2, - 4.0f); + current_tile_canvas_.DrawBitmap( + tile16_blockset_.tile_bitmaps[selected_tile16_], 2, 4.0f); current_tile_canvas_.DrawGrid(16.f); current_tile_canvas_.DrawOverlay(); - gui::InputTileInfo("TL", ¤t_tile16_info.tiles[0]); + gui::InputTileInfo("TL", ¤t_tile16_info[0]); ImGui::SameLine(); - gui::InputTileInfo("TR", ¤t_tile16_info.tiles[1]); - gui::InputTileInfo("BL", ¤t_tile16_info.tiles[2]); + gui::InputTileInfo("TR", ¤t_tile16_info[1]); + gui::InputTileInfo("BL", ¤t_tile16_info[2]); ImGui::SameLine(); - gui::InputTileInfo("BR", ¤t_tile16_info.tiles[3]); + gui::InputTileInfo("BR", ¤t_tile16_info[3]); if (ImGui::Button("Modify Tile16")) { - tile16_sheet_.ModifyTile16( - rom()->graphics_buffer(), current_tile16_info.tiles[0], - current_tile16_info.tiles[1], current_tile16_info.tiles[2], - current_tile16_info.tiles[3], selected_tile16_, 212); - tile16_individual_[selected_tile16_] = - tile16_sheet_.GetTile16(selected_tile16_); - tile16_individual_[selected_tile16_].SetPalette( - *rom()->mutable_dungeon_palette(3)); - Renderer::Get().RenderBitmap( - &tile16_individual_[selected_tile16_]); + gfx::ModifyTile16(tile16_blockset_, rom()->graphics_buffer(), + current_tile16_info[0], current_tile16_info[1], + current_tile16_info[2], current_tile16_info[3], 212, + selected_tile16_); + gfx::UpdateTile16(tile16_blockset_, selected_tile16_); } } ImGui::EndChild(); } void ScreenEditor::DrawDungeonMapsEditor() { - if (ImGui::BeginTable("##DungeonMapToolset", 2, - ImGuiTableFlags_SizingFixedFit)) { - ImGui::TableSetupColumn("Draw Mode"); - ImGui::TableSetupColumn("Edit Mode"); - - ImGui::TableNextColumn(); - if (ImGui::Button(ICON_MD_DRAW)) { - current_mode_ = EditingMode::DRAW; - } - - ImGui::TableNextColumn(); - if (ImGui::Button(ICON_MD_EDIT)) { - current_mode_ = EditingMode::EDIT; - } - - ImGui::EndTable(); + if (ImGui::Button(ICON_MD_DRAW)) { + current_mode_ = EditingMode::DRAW; + } + ImGui::SameLine(); + if (ImGui::Button(ICON_MD_EDIT)) { + current_mode_ = EditingMode::EDIT; + } + ImGui::SameLine(); + if (ImGui::Button(ICON_MD_SAVE)) { + PRINT_IF_ERROR(zelda3::SaveDungeonMapTile16(tile16_blockset_, *rom())); } static std::vector dungeon_names = { @@ -563,8 +386,9 @@ void ScreenEditor::LoadBinaryGfx() { std::vector bin_data((std::istreambuf_iterator(file)), std::istreambuf_iterator()); auto converted_bin = gfx::SnesTo8bppSheet(bin_data, 4, 4); - tile16_sheet_.clear(); - if (LoadDungeonMapTile16(converted_bin, true).ok()) { + if (zelda3::LoadDungeonMapTile16(tile16_blockset_, *rom(), converted_bin, + true) + .ok()) { sheets_.clear(); std::vector> gfx_sheets; for (int i = 0; i < 4; i++) { diff --git a/src/app/editor/graphics/screen_editor.h b/src/app/editor/graphics/screen_editor.h index 3bc25322..cae09358 100644 --- a/src/app/editor/graphics/screen_editor.h +++ b/src/app/editor/graphics/screen_editor.h @@ -8,7 +8,6 @@ #include "app/gfx/bitmap.h" #include "app/gfx/snes_palette.h" #include "app/gfx/tilemap.h" -#include "app/gfx/tilesheet.h" #include "app/gui/canvas.h" #include "app/rom.h" #include "app/zelda3/screen/dungeon_map.h" @@ -50,7 +49,7 @@ class ScreenEditor : public Editor { void set_rom(Rom* rom) { rom_ = rom; } Rom* rom() const { return rom_; } - absl::Status SaveDungeonMaps(); + std::vector dungeon_maps_; private: void DrawTitleScreenEditor(); @@ -61,7 +60,6 @@ class ScreenEditor : public Editor { void DrawToolset(); void DrawInventoryToolset(); - absl::Status LoadDungeonMaps(); absl::Status LoadDungeonMapTile16(const std::vector& gfx_data, bool bin_mode = false); absl::Status SaveDungeonMapTile16(); @@ -79,7 +77,6 @@ class ScreenEditor : public Editor { bool binary_gfx_loaded_ = false; uint8_t selected_room = 0; - uint8_t boss_room = 0; int selected_tile16_ = 0; int selected_tile8_ = 0; @@ -91,14 +88,12 @@ class ScreenEditor : public Editor { std::unordered_map tile16_individual_; std::vector tile8_individual_; - std::vector dungeon_maps_; - std::vector>> dungeon_map_labels_; + zelda3::DungeonMapLabels dungeon_map_labels_; gfx::SnesPalette palette_; gfx::BitmapTable sheets_; - gfx::Tilesheet tile16_sheet_; gfx::Tilemap tile16_blockset_; - gfx::InternalTile16 current_tile16_info; + std::array current_tile16_info; gui::Canvas current_tile_canvas_{"##CurrentTileCanvas", ImVec2(32, 32), gui::CanvasGridSize::k16x16, 2.0f}; diff --git a/src/app/gfx/gfx.cmake b/src/app/gfx/gfx.cmake index 83b22e11..d3bc9ba4 100644 --- a/src/app/gfx/gfx.cmake +++ b/src/app/gfx/gfx.cmake @@ -9,5 +9,4 @@ set( app/gfx/snes_tile.cc app/gfx/snes_color.cc app/gfx/tilemap.cc - app/gfx/tilesheet.cc ) \ No newline at end of file diff --git a/src/app/gfx/tilesheet.cc b/src/app/gfx/tilesheet.cc deleted file mode 100644 index c708c859..00000000 --- a/src/app/gfx/tilesheet.cc +++ /dev/null @@ -1,176 +0,0 @@ -#include "app/gfx/tilesheet.h" - -#include -#include - -#include "app/gfx/bitmap.h" -#include "app/gfx/snes_tile.h" - -namespace yaze { -namespace gfx { - -void Tilesheet::Init(int width, int height, TileType tile_type) { - internal_data_.resize(0x20000); - bitmap_ = std::make_shared(width, height, 8, internal_data_); - tile_type_ = tile_type; - if (tile_type_ == TileType::Tile8) { - tile_width_ = 8; - tile_height_ = 8; - } else { - tile_width_ = 16; - tile_height_ = 16; - } -} - -void Tilesheet::ComposeTile16(const std::vector& graphics_buffer, - const TileInfo& top_left, - const TileInfo& top_right, - const TileInfo& bottom_left, - const TileInfo& bottom_right, int sheet_offset) { - sheet_offset_ = sheet_offset; - // Calculate the base position for this Tile16 in the full-size bitmap - int tiles_per_row = bitmap_->width() / tile_width_; - int tile16_row = num_tiles_ / tiles_per_row; - int tile16_column = num_tiles_ % tiles_per_row; - int base_x = tile16_column * tile_width_; - int base_y = tile16_row * tile_height_; - - // Compose and place each part of the Tile16 - ComposeAndPlaceTilePart(graphics_buffer, top_left, base_x, base_y); - ComposeAndPlaceTilePart(graphics_buffer, top_right, base_x + 8, base_y); - ComposeAndPlaceTilePart(graphics_buffer, bottom_left, base_x, base_y + 8); - ComposeAndPlaceTilePart(graphics_buffer, bottom_right, base_x + 8, - base_y + 8); - - tile_info_.push_back({top_left, top_right, bottom_left, bottom_right}); - - num_tiles_++; -} - -void Tilesheet::ModifyTile16(const std::vector& graphics_buffer, - const TileInfo& top_left, - const TileInfo& top_right, - const TileInfo& bottom_left, - const TileInfo& bottom_right, int tile_id, - int sheet_offset) { - sheet_offset_ = sheet_offset; - // Calculate the base position for this Tile16 in the full-size bitmap - int tiles_per_row = bitmap_->width() / tile_width_; - int tile16_row = tile_id / tiles_per_row; - int tile16_column = tile_id % tiles_per_row; - int base_x = tile16_column * tile_width_; - int base_y = tile16_row * tile_height_; - - // Compose and place each part of the Tile16 - ComposeAndPlaceTilePart(graphics_buffer, top_left, base_x, base_y); - ComposeAndPlaceTilePart(graphics_buffer, top_right, base_x + 8, base_y); - ComposeAndPlaceTilePart(graphics_buffer, bottom_left, base_x, base_y + 8); - ComposeAndPlaceTilePart(graphics_buffer, bottom_right, base_x + 8, - base_y + 8); - - tile_info_[tile_id] = {top_left, top_right, bottom_left, bottom_right}; -} - -void Tilesheet::ComposeAndPlaceTilePart( - const std::vector& graphics_buffer, const TileInfo& tile_info, - int base_x, int base_y) { - std::vector tile_data = - FetchTileDataFromGraphicsBuffer(graphics_buffer, tile_info.id_); - - if (tile_info.vertical_mirror_) { - MirrorTileDataVertically(tile_data); - } - if (tile_info.horizontal_mirror_) { - MirrorTileDataHorizontally(tile_data); - } - - // Place the tile data into the full-size bitmap at the calculated position - for (int y = 0; y < 8; ++y) { - for (int x = 0; x < 8; ++x) { - int src_index = y * 8 + x; - int dest_x = base_x + x; - int dest_y = base_y + y; - int dest_index = (dest_y * bitmap_->width()) + dest_x; - internal_data_[dest_index] = tile_data[src_index]; - } - } - - bitmap_->set_data(internal_data_); -} - -std::vector Tilesheet::FetchTileDataFromGraphicsBuffer( - const std::vector& graphics_buffer, int tile_id) { - const int tile_width = 8; - const int tile_height = 8; - const int buffer_width = 128; - const int sheet_height = 32; - - const int tiles_per_row = buffer_width / tile_width; - const int rows_per_sheet = sheet_height / tile_height; - const int tiles_per_sheet = tiles_per_row * rows_per_sheet; - - // Calculate the position in the graphics_buffer_ based on tile_id - std::vector tile_data(0x40, 0x00); - int sheet = (tile_id / tiles_per_sheet) % 4 + sheet_offset_; - int position_in_sheet = tile_id % tiles_per_sheet; - int row_in_sheet = position_in_sheet / tiles_per_row; - int column_in_sheet = position_in_sheet % tiles_per_row; - - // Ensure that the sheet ID is between 212 and 215 if using full gfx buffer - assert(sheet >= sheet_offset_ && sheet <= sheet_offset_ + 3); - - // Copy the tile data from the graphics_buffer_ to tile_data - for (int y = 0; y < 8; ++y) { - for (int x = 0; x < 8; ++x) { - // Calculate the position in the graphics_buffer_ based on tile_id - int src_x = column_in_sheet * tile_width + x; - int src_y = (sheet * sheet_height) + (row_in_sheet * tile_height) + y; - - int src_index = (src_y * buffer_width) + src_x; - int dest_index = y * tile_width + x; - - tile_data[dest_index] = graphics_buffer[src_index]; - } - } - - return tile_data; -} - -void Tilesheet::MirrorTileDataVertically(std::vector& tile_data) { - std::vector tile_data_copy = tile_data; - for (int i = 0; i < 8; ++i) { // For each row - for (int j = 0; j < 8; ++j) { // For each column - int src_index = i * 8 + j; - int dest_index = (7 - i) * 8 + j; // Calculate the mirrored row - tile_data_copy[dest_index] = tile_data[src_index]; - } - } - tile_data = tile_data_copy; -} - -void Tilesheet::MirrorTileDataHorizontally(std::vector& tile_data) { - std::vector tile_data_copy = tile_data; - for (int i = 0; i < 8; ++i) { // For each row - for (int j = 0; j < 8; ++j) { // For each column - int src_index = i * 8 + j; - int dest_index = i * 8 + (7 - j); // Calculate the mirrored column - tile_data_copy[dest_index] = tile_data[src_index]; - } - } - tile_data = tile_data_copy; -} - -void Tilesheet::MirrorTileData(std::vector& tile_data, bool mirrorX, - bool mirrorY) { - std::vector tile_data_copy = tile_data; - if (mirrorX) { - MirrorTileDataHorizontally(tile_data_copy); - } - if (mirrorY) { - MirrorTileDataVertically(tile_data_copy); - } - tile_data = tile_data_copy; -} - -} // namespace gfx -} // namespace yaze diff --git a/src/app/gfx/tilesheet.h b/src/app/gfx/tilesheet.h deleted file mode 100644 index 81cff193..00000000 --- a/src/app/gfx/tilesheet.h +++ /dev/null @@ -1,133 +0,0 @@ -#ifndef YAZE_APP_GFX_TILESHEET_H -#define YAZE_APP_GFX_TILESHEET_H - -#include -#include - -#include "app/gfx/bitmap.h" -#include "app/gfx/snes_palette.h" -#include "app/gfx/snes_tile.h" - -namespace yaze { -namespace gfx { - -enum class TileType { Tile8, Tile16 }; - -struct InternalTile16 { - std::array tiles; -}; - -/** - * @class Tilesheet - * @brief Represents a tilesheet, which is a collection of tiles stored in a - * bitmap. - * - * The Tilesheet class provides methods to manipulate and extract tiles from the - * tilesheet. It also supports copying and mirroring tiles within the tilesheet. - */ -class Tilesheet { - public: - Tilesheet() = default; - Tilesheet(std::shared_ptr bitmap, int tileWidth, int tileHeight, - TileType tile_type) - : bitmap_(std::move(bitmap)), - tile_width_(tileWidth), - tile_height_(tileHeight), - tile_type_(tile_type) {} - - void Init(int width, int height, TileType tile_type); - - void ComposeTile16(const std::vector& graphics_buffer, - const TileInfo& top_left, const TileInfo& top_right, - const TileInfo& bottom_left, const TileInfo& bottom_right, - int sheet_offset = 0); - void ModifyTile16(const std::vector& graphics_buffer, - const TileInfo& top_left, const TileInfo& top_right, - const TileInfo& bottom_left, const TileInfo& bottom_right, - int tile_id, int sheet_offset = 0); - - void ComposeAndPlaceTilePart(const std::vector& graphics_buffer, - const TileInfo& tile_info, int baseX, int baseY); - - // Extracts a tile from the tilesheet - Bitmap GetTile(int tileX, int tileY, int bmp_width, int bmp_height) { - std::vector tileData(tile_width_ * tile_height_); - int tile_data_offset = 0; - bitmap_->Get8x8Tile(CalculateTileIndex(tileX, tileY), tileX, tileY, - tileData, tile_data_offset); - return Bitmap(bmp_width, bmp_height, bitmap_->depth(), tileData); - } - - Bitmap GetTile16(int tile_id) { - int tiles_per_row = bitmap_->width() / tile_width_; - int tile_x = (tile_id % tiles_per_row) * tile_width_; - int tile_y = (tile_id / tiles_per_row) * tile_height_; - std::vector tile_data(tile_width_ * tile_height_, 0x00); - int tile_data_offset = 0; - bitmap_->Get16x16Tile(tile_x, tile_y, tile_data, tile_data_offset); - return Bitmap(16, 16, bitmap_->depth(), tile_data); - } - - // Copy a tile within the tilesheet - void CopyTile(int srcX, int srcY, int destX, int destY, bool mirror_x = false, - bool mirror_y = false) { - auto src_tile = GetTile(srcX, srcY, tile_width_, tile_height_); - auto dest_tile_data = src_tile.vector(); - MirrorTileData(dest_tile_data, mirror_x, mirror_y); - WriteTile(destX, destY, dest_tile_data); - } - - auto bitmap() const { return bitmap_; } - auto mutable_bitmap() { return bitmap_; } - auto num_tiles() const { return num_tiles_; } - auto tile_width() const { return tile_width_; } - auto tile_height() const { return tile_height_; } - auto set_palette(gfx::SnesPalette& palette) { palette_ = palette; } - auto palette() const { return palette_; } - auto tile_type() const { return tile_type_; } - auto tile_info() const { return tile_info_; } - auto mutable_tile_info() { return tile_info_; } - void clear() { - palette_.clear(); - internal_data_.clear(); - tile_info_.clear(); - bitmap_.reset(); - num_tiles_ = 0; - } - - private: - int CalculateTileIndex(int x, int y) { - return y * (bitmap_->width() / tile_width_) + x; - } - - std::vector FetchTileDataFromGraphicsBuffer( - const std::vector& graphics_buffer, int tile_id); - - void MirrorTileDataVertically(std::vector& tileData); - void MirrorTileDataHorizontally(std::vector& tileData); - void MirrorTileData(std::vector& tileData, bool mirror_x, - bool mirror_y); - - void WriteTile(int x, int y, const std::vector& tileData) { - int tileDataOffset = 0; - bitmap_->Get8x8Tile(CalculateTileIndex(x, y), x, y, - const_cast&>(tileData), - tileDataOffset); - } - - int num_tiles_ = 0; - int tile_width_ = 0; - int tile_height_ = 0; - int sheet_offset_ = 0; - - TileType tile_type_; - SnesPalette palette_; - std::vector internal_data_; - std::vector tile_info_; - std::shared_ptr bitmap_; -}; - -} // namespace gfx -} // namespace yaze - -#endif // YAZE_APP_GFX_TILESHEET_H