diff --git a/src/app/editor/dungeon_editor.cc b/src/app/editor/dungeon_editor.cc index 151c2736..d8a8c100 100644 --- a/src/app/editor/dungeon_editor.cc +++ b/src/app/editor/dungeon_editor.cc @@ -8,6 +8,24 @@ namespace editor { void DungeonEditor::Update() { DrawToolset(); + + ImGui::Separator(); + if (ImGui::BeginTable("#DungeonEditTable", 2, toolset_table_flags_, + ImVec2(0, 0))) { + ImGui::TableSetupColumn("Canvas", ImGuiTableColumnFlags_WidthStretch, + ImGui::GetContentRegionAvail().x); + ImGui::TableSetupColumn("Object Selector"); + ImGui::TableHeadersRow(); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + DrawDungeonCanvas(); + ImGui::TableNextColumn(); + DrawTileSelector(); + ImGui::EndTable(); + } +} + +void DungeonEditor::DrawDungeonCanvas() { canvas_.DrawBackground(); canvas_.DrawContextMenu(); canvas_.DrawGrid(); @@ -56,6 +74,30 @@ void DungeonEditor::DrawToolset() { } } +void DungeonEditor::DrawRoomGraphics() { + room_gfx_canvas_.DrawBackground(ImVec2(256 + 1, 0x10 * 0x40 + 1)); + room_gfx_canvas_.DrawContextMenu(); + room_gfx_canvas_.DrawTileSelector(32); + room_gfx_canvas_.DrawBitmap(room_gfx_bmp_, 2, is_loaded_); + room_gfx_canvas_.DrawGrid(32.0f); + room_gfx_canvas_.DrawOverlay(); +} + +void DungeonEditor::DrawTileSelector() { + if (ImGui::BeginTabBar("##TabBar", ImGuiTabBarFlags_FittingPolicyScroll)) { + if (ImGui::BeginTabItem("Room Graphics")) { + if (ImGuiID child_id = ImGui::GetID((void *)(intptr_t)3); + ImGui::BeginChild(child_id, ImGui::GetContentRegionAvail(), true, + ImGuiWindowFlags_AlwaysVerticalScrollbar)) { + DrawRoomGraphics(); + } + ImGui::EndChild(); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } +} + } // namespace editor } // namespace app } // namespace yaze \ No newline at end of file diff --git a/src/app/editor/dungeon_editor.h b/src/app/editor/dungeon_editor.h index 5c000d2d..a0e98474 100644 --- a/src/app/editor/dungeon_editor.h +++ b/src/app/editor/dungeon_editor.h @@ -5,6 +5,8 @@ #include "gui/canvas.h" #include "gui/icons.h" +#include "rom.h" +#include "zelda3/dungeon/room.h" namespace yaze { namespace app { @@ -16,7 +18,18 @@ class DungeonEditor { private: void DrawToolset(); + void DrawDungeonCanvas(); + void DrawRoomGraphics(); + void DrawTileSelector(); + + bool is_loaded_ = false; + + gfx::Bitmap room_gfx_bmp_; + + std::vector rooms_; + gui::Canvas canvas_; + gui::Canvas room_gfx_canvas_; ImGuiTableFlags toolset_table_flags_ = ImGuiTableFlags_SizingFixedFit; }; } // namespace editor diff --git a/src/app/gfx/bitmap.h b/src/app/gfx/bitmap.h index 9ae90ee3..169341a9 100644 --- a/src/app/gfx/bitmap.h +++ b/src/app/gfx/bitmap.h @@ -80,6 +80,8 @@ class Bitmap { std::shared_ptr surface_ = nullptr; }; +using BitmapTable = std::unordered_map; + } // namespace gfx } // namespace app } // namespace yaze diff --git a/src/app/rom.h b/src/app/rom.h index a8266274..b4bfc614 100644 --- a/src/app/rom.h +++ b/src/app/rom.h @@ -99,15 +99,13 @@ class ROM { void Write(int addr, int value); void WriteShort(int addr, int value); - void RenderBitmap(gfx::Bitmap* bitmap) const; - absl::Status ApplyAssembly(const absl::string_view& filename, size_t patch_size); absl::Status PatchOverworldMosaic(char mosaic_tiles[core::kNumOverworldMaps], int routine_offset); auto GetTitle() const { return title; } - auto GetGraphicsBin() const { return graphics_bin_; } + gfx::BitmapTable GetGraphicsBin() const { return graphics_bin_; } auto GetGraphicsBuffer() const { return graphics_buffer_; } auto GetPaletteGroup(std::string group) { return palette_groups_[group]; } void SetupRenderer(std::shared_ptr renderer) { @@ -140,17 +138,23 @@ class ROM { return (ushort)((rom_data_[offset + 1]) << 8) | rom_data_[offset]; } + void RenderBitmap(gfx::Bitmap* bitmap) const { + bitmap->CreateTexture(renderer_); + } + private: long size_ = 0; uchar title[21] = "ROM Not Loaded"; - bool is_loaded_ = false; bool isbpp3[223]; + bool is_loaded_ = false; std::string filename_; Bytes rom_data_; Bytes graphics_buffer_; + + gfx::BitmapTable graphics_bin_; + std::shared_ptr renderer_; - std::unordered_map graphics_bin_; std::unordered_map palette_groups_; }; diff --git a/src/app/zelda3/dungeon/room.cc b/src/app/zelda3/dungeon/room.cc index fb738897..90021eea 100644 --- a/src/app/zelda3/dungeon/room.cc +++ b/src/app/zelda3/dungeon/room.cc @@ -12,6 +12,68 @@ namespace app { namespace zelda3 { namespace dungeon { +void Room::LoadGfxGroups() { + int gfxPointer = + (rom_[gfx_groups_pointer + 1] << 8) + rom_[gfx_groups_pointer]; + gfxPointer = core::SnesToPc(gfxPointer); + + for (int i = 0; i < 37; i++) { + for (int j = 0; j < 8; j++) { + mainGfx[i][j] = rom_[gfxPointer + (i * 8) + j]; + } + } + + for (int i = 0; i < 82; i++) { + for (int j = 0; j < 4; j++) { + roomGfx[i][j] = rom_[entrance_gfx_group + (i * 4) + j]; + } + } + + for (int i = 0; i < 144; i++) { + for (int j = 0; j < 4; j++) { + spriteGfx[i][j] = rom_[sprite_blockset_pointer + (i * 4) + j]; + } + } + + for (int i = 0; i < 72; i++) { + for (int j = 0; j < 4; j++) { + paletteGfx[i][j] = rom_[dungeons_palettes_groups + (i * 4) + j]; + } + } +} + +bool Room::SaveGroupsToROM() { + int gfxPointer = + (rom_[gfx_groups_pointer + 1] << 8) + rom_[gfx_groups_pointer]; + gfxPointer = core::SnesToPc(gfxPointer); + + for (int i = 0; i < 37; i++) { + for (int j = 0; j < 8; j++) { + rom_.Write(gfxPointer + (i * 8) + j, mainGfx[i][j]); + } + } + + for (int i = 0; i < 82; i++) { + for (int j = 0; j < 4; j++) { + rom_.Write(entrance_gfx_group + (i * 4) + j, roomGfx[i][j]); + } + } + + for (int i = 0; i < 144; i++) { + for (int j = 0; j < 4; j++) { + rom_.Write(sprite_blockset_pointer + (i * 4) + j, spriteGfx[i][j]); + } + } + + for (int i = 0; i < 72; i++) { + for (int j = 0; j < 4; j++) { + rom_.Write(dungeons_palettes_groups + (i * 4) + j, paletteGfx[i][j]); + } + } + + return false; +} + void Room::LoadChests() {} void Room::LoadBlocks() {} @@ -20,12 +82,82 @@ void Room::LoadTorches() {} void Room::LoadSecrets() {} -void Room::Resync() {} +void Room::Resync() {} void Room::LoadObjectsFromArray(int loc) {} void Room::LoadSpritesFromArray(int loc) {} +void Room::LoadRoomGraphics(uchar entrance_blockset) { + for (int i = 0; i < 8; i++) { + blocks[i] = mainGfx[BackgroundTileset][i]; + if (i >= 6 && i <= 6) { + // 3-6 + if (entrance_blockset != 0xFF) { + // 6 is wrong for the entrance? -NOP need to fix that + // TODO: Find why this is wrong - Thats because of the stairs need to + // find a workaround + if (roomGfx[entrance_blockset][i - 3] != 0) { + blocks[i] = roomGfx[entrance_blockset][i - 3]; + } + } + } + } + + blocks[8] = 115 + 0; // Static Sprites Blocksets (fairy,pot,ect...) + blocks[9] = 115 + 10; + blocks[10] = 115 + 6; + blocks[11] = 115 + 7; + for (int i = 0; i < 4; i++) { + blocks[12 + i] = (uchar)(spriteGfx[SpriteTileset + 64][i] + 115); + } // 12-16 sprites + + auto newPdata = rom_.GetGraphicsBuffer(); + + uchar* sheetsData = current_graphics_.GetData(); + // Into "room gfx16" 16 of them + + int sheetPos = 0; + for (int i = 0; i < 16; i++) { + int d = 0; + int ioff = blocks[i] * 2048; + while (d < 2048) { + // NOTE LOAD BLOCKSETS SOMEWHERE FIRST + uchar mapByte = newPdata[d + ioff]; + if (i < 4) // removed switch + { + mapByte += 0x88; + } // Last line of 6, first line of 7 ? + + sheetsData[d + sheetPos] = mapByte; + d++; + } + + sheetPos += 2048; + } + + LoadAnimatedGraphics(); +} + +void Room::LoadAnimatedGraphics() { + int gfxanimatedPointer = core::SnesToPc(gfx_animated_pointer); + + auto newPdata = rom_.GetGraphicsBuffer(); + + uchar* sheetsData = current_graphics_.GetData(); + int data = 0; + while (data < 512) { + uchar mapByte = newPdata[data + (92 * 2048) + (512 * animated_frame)]; + sheetsData[data + (7 * 2048)] = mapByte; + + mapByte = + newPdata[data + (rom_[gfxanimatedPointer + BackgroundTileset] * 2048) + + (512 * animated_frame)]; + sheetsData[data + (7 * 2048) - 512] = mapByte; + data++; + } +} + void Room::LoadRoomFromROM() { // Load dungeon header int headerPointer = core::SnesToPc(room_header_pointer); diff --git a/src/app/zelda3/dungeon/room.h b/src/app/zelda3/dungeon/room.h index 65eff47b..e9752a07 100644 --- a/src/app/zelda3/dungeon/room.h +++ b/src/app/zelda3/dungeon/room.h @@ -13,6 +13,9 @@ namespace app { namespace zelda3 { namespace dungeon { +constexpr int entrance_gfx_group = 0x5D97; +constexpr int gfx_animated_pointer = 0x10275; // JP 0x10624 //long pointer + class DungeonDestination { public: DungeonDestination(uint8_t i) : Index(i) {} @@ -85,6 +88,8 @@ class Room { Room() = default; private: + void LoadGfxGroups(); + bool SaveGroupsToROM(); void LoadChests(); void LoadBlocks(); void LoadTorches(); @@ -94,6 +99,9 @@ class Room { void LoadObjectsFromArray(int loc); void LoadSpritesFromArray(int loc); + void LoadRoomGraphics(uchar entrance_blockset = 0xFF); + void LoadAnimatedGraphics(); + void LoadRoomFromROM(); DungeonDestination Pits; @@ -102,6 +110,8 @@ class Room { DungeonDestination Stair3; DungeonDestination Stair4; + int animated_frame = 0; + int RoomID = 0; ushort MessageID = 0; uchar BackgroundTileset; @@ -111,6 +121,12 @@ class Room { uchar Floor1Graphics; uchar Floor2Graphics; uchar Layer2Mode; + std::array blocks; + + uint8_t mainGfx[37][8]; + uint8_t roomGfx[82][4]; + uint8_t spriteGfx[144][4]; + uint8_t paletteGfx[72][4]; // LayerMergeType LayerMerging; uchar Tag1; @@ -118,6 +134,8 @@ class Room { bool IsDark; ROM rom_; + + gfx::Bitmap current_graphics_; }; } // namespace dungeon