diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9d47e203..c660273d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -36,12 +36,35 @@ set( # Asar Assembly --------------------------------------------------------------- add_subdirectory(lib/asar/src) -set(ASAR_GEN_EXE OFF) -set(ASAR_GEN_DLL ON) -set(ASAR_GEN_LIB OFF) +get_target_property(ASAR_INCLUDE_DIR asar-static INCLUDE_DIRECTORIES) +target_include_directories(asar-static PRIVATE ${ASAR_INCLUDE_DIR}) +set(ASAR_GEN_EXE OFF) +set(ASAR_GEN_DLL ON) +set(ASAR_GEN_LIB ON) set(ASAR_GEN_EXE_TEST OFF) set(ASAR_GEN_DLL_TEST OFF) +set(ASAR_STATIC_SRC + "lib/asar/src/asar/interface-lib.cpp" + "lib/asar/src/asar/addr2line.cpp" + "lib/asar/src/asar/arch-65816.cpp" + "lib/asar/src/asar/arch-spc700.cpp" + "lib/asar/src/asar/arch-superfx.cpp" + "lib/asar/src/asar/assembleblock.cpp" + "lib/asar/src/asar/crc32.cpp" + "lib/asar/src/asar/libcon.cpp" + "lib/asar/src/asar/libsmw.cpp" + "lib/asar/src/asar/libstr.cpp" + "lib/asar/src/asar/macro.cpp" + "lib/asar/src/asar/main.cpp" + "lib/asar/src/asar/asar_math.cpp" + "lib/asar/src/asar/virtualfile.cpp" + "lib/asar/src/asar/warnings.cpp" + "lib/asar/src/asar/errors.cpp" + "lib/asar/src/asar/platform/file-helpers.cpp" + "lib/asar/src/asar/platform/linux/file-helpers-linux.cpp" +) + # yaze source files ----------------------------------------------------------- set( YAZE_APP_CORE_SRC @@ -86,6 +109,7 @@ set( gui/input.cc gui/style.cc gui/widgets.cc + gui/color.cc ) add_executable( @@ -99,7 +123,7 @@ add_executable( ${YAZE_APP_ZELDA3_SRC} ${YAZE_GUI_SRC} ${IMGUI_SRC} - lib/asar/src/asar-dll-bindings/c/asardll.c + ${ASAR_STATIC_SRC} ) target_include_directories( @@ -111,7 +135,7 @@ target_include_directories( ${PNG_INCLUDE_DIRS} ${SDL2_INCLUDE_DIR} ${GLEW_INCLUDE_DIRS} - lib/asar/src/asar-dll-bindings/c + lib/asar/src/ ) set(SDL_TARGETS SDL2::SDL2) @@ -130,7 +154,10 @@ target_link_libraries( ${OPENGL_LIBRARIES} ${CMAKE_DL_LIBS} ImGui + asar-static ) +target_compile_definitions(yaze PRIVATE "linux") +target_compile_definitions(yaze PRIVATE "stricmp=strcasecmp") set_target_properties(yaze PROPERTIES @@ -155,7 +182,6 @@ add_executable( ${YAZE_APP_ZELDA3_SRC} ${YAZE_GUI_SRC} ${IMGUI_SRC} - lib/asar/src/asar-dll-bindings/c/asardll.c ) target_include_directories( @@ -167,7 +193,7 @@ target_include_directories( ${PNG_INCLUDE_DIRS} ${SDL2_INCLUDE_DIR} ${GLEW_INCLUDE_DIRS} - lib/asar/src/asar-dll-bindings/c + ${ASAR_STATIC_SRC} ) target_link_libraries( @@ -179,6 +205,7 @@ target_link_libraries( ${OPENGL_LIBRARIES} ${CMAKE_DL_LIBS} delta-service + asar-static ImGui ) diff --git a/src/app/asm/script.cc b/src/app/asm/script.cc index 1972e958..ff0cf404 100644 --- a/src/app/asm/script.cc +++ b/src/app/asm/script.cc @@ -1,6 +1,6 @@ #include "script.h" -#include +#include #include #include @@ -20,49 +20,13 @@ namespace yaze { namespace app { namespace snes_asm { -std::string GenerateBytePool(char mosaic_tiles[core::kNumOverworldMaps]) { - std::string to_return = ""; - int column = 0; - for (int i = 0; i < core::kNumOverworldMaps; ++i) { - std::string to_add = ""; - - // if start of line, define byte - if (i == 0 || i % 8 == 0) { - to_add += " db "; - } - - // set byte - to_add += "$00"; - if (mosaic_tiles[i] > 0) { - if (i == 0 || i % 8 == 0) { - to_add = " db $01"; - } else { - to_add = "$01"; - } - } - - // newline or comma separated - if (column == 7) { - column = 0; - to_add += " \n"; - } else { - column++; - to_add += ", "; - } - - to_return += to_add; - } - return to_return; -} - absl::Status Script::ApplyPatchToROM(ROM &rom) { if (patch_contents_.empty() || patch_filename_.empty()) { return absl::InvalidArgumentError("No patch loaded!"); } - - char *data = (char *)rom.data(); - int size = rom.GetSize(); int count = 0; + auto data = (char *)rom.data(); + int size = rom.size(); if (!asar_patch(patch_filename_.c_str(), data, patch_size_, &size)) { auto asar_error = asar_geterrors(&count); auto full_error = asar_error->fullerrdata; @@ -71,43 +35,37 @@ absl::Status Script::ApplyPatchToROM(ROM &rom) { return absl::OkStatus(); } -absl::Status Script::GenerateMosaicChangeAssembly( +absl::Status Script::PatchOverworldMosaic( ROM &rom, char mosaic_tiles[core::kNumOverworldMaps], int routine_offset, int hook_offset) { + for (int i = 0; i < core::kNumOverworldMaps; i++) { + if (mosaic_tiles[i]) { + rom[core::overworldCustomMosaicArray + i] = 0x01; + } else { + rom[core::overworldCustomMosaicArray + i] = 0x00; + } + } std::fstream file("assets/asm/mosaic_change.asm", std::ios::out | std::ios::in); if (!file.is_open()) { return absl::InvalidArgumentError( - "Couldn't open mosaic change template file"); + "Unable to open mosaic change assembly source"); } - std::stringstream assembly; assembly << file.rdbuf(); file.close(); - auto assembly_string = assembly.str(); - if (!core::StringReplace(assembly_string, "", kMosaicChangeOffset)) { return absl::InternalError( "Mosaic template did not have proper `` to replace."); } - if (!core::StringReplace( assembly_string, "", absl::StrFormat("$%x", routine_offset + kSNESToPCOffset))) { return absl::InternalError( "Mosaic template did not have proper `` to replace."); } - - assembly_string += GenerateBytePool(mosaic_tiles); patch_contents_ = assembly_string; - patch_filename_ = "assets/asm/mosaic_change_generated.asm"; - std::ofstream new_file(patch_filename_, std::ios::out); - if (new_file.is_open()) { - new_file.write(assembly_string.c_str(), assembly_string.size()); - new_file.close(); - } - return ApplyPatchToROM(rom); } diff --git a/src/app/asm/script.h b/src/app/asm/script.h index ede1ba36..15a2b5cf 100644 --- a/src/app/asm/script.h +++ b/src/app/asm/script.h @@ -1,7 +1,7 @@ #ifndef YAZE_APP_ASM_SCRIPT_H #define YAZE_APP_ASM_SCRIPT_H -#include +#include #include #include @@ -27,17 +27,15 @@ class ScriptTemplate { public: virtual ~ScriptTemplate() = default; virtual absl::Status ApplyPatchToROM(ROM& rom) = 0; - virtual absl::Status GenerateMosaicChangeAssembly( + virtual absl::Status PatchOverworldMosaic( ROM& rom, char mosaic_tiles[core::kNumOverworldMaps], int routine_offset, int hook_offset = 0) = 0; }; class Script : public ScriptTemplate { public: - Script() { asar_init_with_dll_path("assets/libasar.dll"); } - absl::Status ApplyPatchToROM(ROM& rom) override; - absl::Status GenerateMosaicChangeAssembly( + absl::Status PatchOverworldMosaic( ROM& rom, char mosaic_tiles[core::kNumOverworldMaps], int routine_offset, int hook_offset = 0) override; diff --git a/src/app/core/constants.h b/src/app/core/constants.h index aeff07c7..94f957ba 100644 --- a/src/app/core/constants.h +++ b/src/app/core/constants.h @@ -482,7 +482,7 @@ constexpr int customAreaSpecificBGPalette = constexpr int customAreaSpecificBGASM = 0x140150; constexpr int customAreaSpecificBGEnabled = 0x140140; // 1 byte, not 0 if enabled - +constexpr int overworldCustomMosaicArray = 0x1301F0; // ============================================================================ // Dungeon Map Related Variables // ============================================================================ diff --git a/src/app/delta/viewer.cc b/src/app/delta/viewer.cc index b1466560..c3848ebe 100644 --- a/src/app/delta/viewer.cc +++ b/src/app/delta/viewer.cc @@ -127,7 +127,7 @@ void Viewer::DrawViewMenu() { if (show_memory_editor) { static MemoryEditor mem_edit; - mem_edit.DrawWindow("Memory Editor", (void*)&rom_, rom_.GetSize()); + mem_edit.DrawWindow("Memory Editor", (void*)&rom_, rom_.size()); } if (show_imgui_demo) { diff --git a/src/app/editor/master_editor.cc b/src/app/editor/master_editor.cc index 59a8a363..14dbcb4f 100644 --- a/src/app/editor/master_editor.cc +++ b/src/app/editor/master_editor.cc @@ -138,7 +138,7 @@ void MasterEditor::DrawInfoPopup() { if (ImGui::BeginPopupModal("ROM Information", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::Text("Title: %s", rom_.GetTitle()); - ImGui::Text("ROM Size: %ld", rom_.GetSize()); + ImGui::Text("ROM Size: %ld", rom_.size()); if (ImGui::Button("Close", ImVec2(200, 0))) { rom_info_ = false; @@ -216,7 +216,7 @@ void MasterEditor::DrawViewMenu() { if (show_memory_editor) { static MemoryEditor mem_edit; - mem_edit.DrawWindow("Memory Editor", (void *)&rom_, rom_.GetSize()); + mem_edit.DrawWindow("Memory Editor", (void *)&rom_, rom_.size()); } if (show_imgui_demo) { diff --git a/src/app/editor/overworld_editor.cc b/src/app/editor/overworld_editor.cc index 1477176e..3e606b76 100644 --- a/src/app/editor/overworld_editor.cc +++ b/src/app/editor/overworld_editor.cc @@ -107,7 +107,7 @@ absl::Status OverworldEditor::DrawToolset() { BUTTON_COLUMN(ICON_MD_ZOOM_OUT) // Zoom Out BUTTON_COLUMN(ICON_MD_ZOOM_IN) // Zoom In TEXT_COLUMN(ICON_MD_MORE_VERT) // Separator - BUTTON_COLUMN(ICON_MD_DRAW); // Draw Tile + BUTTON_COLUMN(ICON_MD_DRAW) // Draw Tile BUTTON_COLUMN(ICON_MD_DOOR_FRONT) // Entrances BUTTON_COLUMN(ICON_MD_DOOR_BACK) // Exits BUTTON_COLUMN(ICON_MD_GRASS) // Items diff --git a/src/app/editor/screen_editor.cc b/src/app/editor/screen_editor.cc index 34505b2c..d81b6262 100644 --- a/src/app/editor/screen_editor.cc +++ b/src/app/editor/screen_editor.cc @@ -17,6 +17,7 @@ #include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" #include "gui/canvas.h" +#include "gui/icons.h" #include "gui/input.h" namespace yaze { @@ -63,37 +64,40 @@ void ScreenEditor::DrawInventoryMenuEditor() { TAB_ITEM("Inventory Menu") static bool create = false; - if (!create) { - PRINT_IF_ERROR(rom_.LoadAllGraphicsData()) - all_gfx_ = rom_.GetGraphicsBuffer(); - inventory_.Create(all_gfx_); + if (!create && rom_.isLoaded()) { + inventory_.Create(); + palette_ =inventory_.Palette(); create = true; } - if (ImGui::BeginTable("InventoryScreen", 2, ImGuiTableFlags_Resizable)) { + DrawInventoryToolset(); + + if (ImGui::BeginTable("InventoryScreen", 3, ImGuiTableFlags_Resizable)) { ImGui::TableSetupColumn("Canvas"); ImGui::TableSetupColumn("Tiles"); + ImGui::TableSetupColumn("Palette"); ImGui::TableHeadersRow(); ImGui::TableNextColumn(); screen_canvas_.DrawBackground(); screen_canvas_.DrawContextMenu(); screen_canvas_.DrawBitmap(inventory_.Bitmap(), 2, create); - screen_canvas_.DrawGrid(); + screen_canvas_.DrawGrid(32.0f); screen_canvas_.DrawOverlay(); ImGui::TableNextColumn(); - tilesheet_canvas_.DrawBackground(ImVec2(128 * 2 + 2, 192 * 2 + 2)); + tilesheet_canvas_.DrawBackground(ImVec2(128 * 2 + 2, (192 * 2) + 4)); tilesheet_canvas_.DrawContextMenu(); tilesheet_canvas_.DrawBitmap(inventory_.Tilesheet(), 2, create); tilesheet_canvas_.DrawGrid(16.0f); tilesheet_canvas_.DrawOverlay(); + ImGui::TableNextColumn(); + gui::DisplayPalette(palette_, create); + ImGui::EndTable(); } - - ImGui::SameLine(); - + ImGui::Separator(); END_TAB_ITEM() } @@ -138,7 +142,7 @@ void ScreenEditor::DrawMosaicEditor() { gui::InputHex("Routine Location", &overworldCustomMosaicASM); if (ImGui::Button("Generate Mosaic Assembly")) { - auto mosaic = mosaic_script_.GenerateMosaicChangeAssembly( + auto mosaic = mosaic_script_.PatchOverworldMosaic( rom_, mosaic_tiles_, overworldCustomMosaicASM); if (!mosaic.ok()) { std::cout << mosaic; @@ -168,6 +172,30 @@ void ScreenEditor::DrawToolset() { ImGui::Checkbox("Draw BG3", &drawing_bg3); } +void ScreenEditor::DrawInventoryToolset() { + if (ImGui::BeginTable("InventoryToolset", 8, ImGuiTableFlags_SizingFixedFit, ImVec2(0, 0))) { + ImGui::TableSetupColumn("#drawTool"); + ImGui::TableSetupColumn("#sep1"); + ImGui::TableSetupColumn("#zoomOut"); + ImGui::TableSetupColumn("#zoomIN"); + ImGui::TableSetupColumn("#sep2"); + ImGui::TableSetupColumn("#bg2Tool"); + ImGui::TableSetupColumn("#bg3Tool"); + ImGui::TableSetupColumn("#itemTool"); + + BUTTON_COLUMN(ICON_MD_UNDO) + BUTTON_COLUMN(ICON_MD_REDO) + TEXT_COLUMN(ICON_MD_MORE_VERT) + BUTTON_COLUMN(ICON_MD_ZOOM_OUT) + BUTTON_COLUMN(ICON_MD_ZOOM_IN) + TEXT_COLUMN(ICON_MD_MORE_VERT) + BUTTON_COLUMN(ICON_MD_DRAW) + BUTTON_COLUMN(ICON_MD_BUILD) + + ImGui::EndTable(); + } +} + } // namespace editor } // namespace app } // namespace yaze \ No newline at end of file diff --git a/src/app/editor/screen_editor.h b/src/app/editor/screen_editor.h index 46b0fbfa..c6635dec 100644 --- a/src/app/editor/screen_editor.h +++ b/src/app/editor/screen_editor.h @@ -9,9 +9,12 @@ #include "app/core/constants.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" +#include "app/gfx/snes_palette.h" #include "app/rom.h" #include "app/zelda3/inventory.h" #include "gui/canvas.h" +#include "gui/icons.h" +#include "gui/color.h" namespace yaze { namespace app { @@ -19,7 +22,6 @@ namespace editor { using MosaicArray = std::array; static int overworldCustomMosaicASM = 0x1301D0; -static int overworldCustomMosaicArray = 0x1301F0; class ScreenEditor { public: @@ -39,6 +41,7 @@ class ScreenEditor { void DrawInventoryMenuEditor(); void DrawToolset(); + void DrawInventoryToolset(); void DrawWorldGrid(int world, int h = 8, int w = 8); char mosaic_tiles_[core::kNumOverworldMaps]; @@ -46,6 +49,7 @@ class ScreenEditor { ROM rom_; Bytes all_gfx_; zelda3::Inventory inventory_; + gfx::SNESPalette palette_; snes_asm::Script mosaic_script_; gui::Canvas screen_canvas_; gui::Canvas tilesheet_canvas_; diff --git a/src/app/rom.cc b/src/app/rom.cc index 067add26..139f37ab 100644 --- a/src/app/rom.cc +++ b/src/app/rom.cc @@ -302,7 +302,7 @@ absl::Status ValidateCompressionResult( RETURN_IF_ERROR(temp_rom.LoadFromBytes( CreateCompressionString(compressed_chain_start->next, mode))) ASSIGN_OR_RETURN(auto decomp_data, - temp_rom.Decompress(0, temp_rom.GetSize())) + temp_rom.Decompress(0, temp_rom.size())) if (!std::equal(decomp_data.begin() + start, decomp_data.end(), temp_rom.begin())) { return absl::InternalError(absl::StrFormat( @@ -352,7 +352,7 @@ int GetGraphicsAddress(const uchar* data, uint8_t offset) { return core::SnesToPc(snes_addr); } -Bytes SNES3bppTo8bppSheet(Bytes sheet, int bpp) { +Bytes SnesTo8bppSheet(Bytes sheet, int bpp) { int xx = 0; // positions where we are at on the sheet int yy = 0; int pos = 0; @@ -368,12 +368,9 @@ Bytes SNES3bppTo8bppSheet(Bytes sheet, int bpp) { } Bytes sheet_buffer_out(buffer_size); - // for each tiles, 16 per line - for (int i = 0; i < num_tiles; i++) { - // for each line - for (int y = 0; y < 8; y++) { - //[0] + [1] + [16] - for (int x = 0; x < 8; x++) { + for (int i = 0; i < num_tiles; i++) { // for each tiles, 16 per line + for (int y = 0; y < 8; y++) { // for each line + for (int x = 0; x < 8; x++) { //[0] + [1] + [16] auto b1 = ((sheet[(y * 2) + (bpp * pos)] & (kGraphicsBitmap[x]))); auto b2 = (sheet[((y * 2) + (bpp * pos)) + 1] & (kGraphicsBitmap[x])); auto b3 = (sheet[(16 + y) + (bpp * pos)] & (kGraphicsBitmap[x])); @@ -457,7 +454,6 @@ absl::StatusOr ROM::Compress(const int start, const int length, int mode, comp_accumulator = 0; } } else { - // Anything is better than directly copying bytes... lc_lz2::CompressionCommandAlternative( rom_data_.data(), compressed_chain, cmd_size, cmd_args, src_data_pos, comp_accumulator, cmd_with_max, max_win); @@ -474,8 +470,8 @@ absl::StatusOr ROM::Compress(const int start, const int length, int mode, } } - lc_lz2::MergeCopy( - compressed_chain_start->next); // Skipping compression chain header + // Skipping compression chain header + lc_lz2::MergeCopy(compressed_chain_start->next); lc_lz2::PrintCompressionChain(compressed_chain_start); return lc_lz2::CreateCompressionString(compressed_chain_start->next, mode); } @@ -515,10 +511,8 @@ absl::StatusOr ROM::Decompress(int offset, int size, int mode) { offset += length; break; case kCommandByteFill: - for (int i = 0; i < length; i++) { - buffer[buffer_pos] = rom_data_[offset]; - buffer_pos++; - } + memset(buffer.data() + buffer_pos, (int)(rom_data_[offset]), length); + buffer_pos += length; offset += 1; // Advances 1 byte in the ROM break; case kCommandWordFill: { @@ -543,35 +537,23 @@ absl::StatusOr ROM::Decompress(int offset, int size, int mode) { ushort s1 = ((rom_data_[offset + 1] & kSnesByteMax) << 8); ushort s2 = ((rom_data_[offset] & kSnesByteMax)); int addr = (s1 | s2); - if (mode == kNintendoMode1) { // Reversed byte order for overworld maps - // addr = (s2 | s1); addr = (rom_data_[offset + 1] & kSnesByteMax) | ((rom_data_[offset] & kSnesByteMax) << 8); - if (addr > offset) { - return absl::InternalError(absl::StrFormat( - "Decompress: Offset for command copy exceeds current position " - "(Offset : %#04x | Pos : %#06x)\n", - addr, offset)); - } - - if (buffer_pos + length >= size) { - size *= 2; - buffer.resize(size); - } - - memcpy(buffer.data() + buffer_pos, buffer.data() + addr, length); - buffer_pos += length; - offset += 2; - break; } - - for (int i = 0; i < length; i++) { - buffer[buffer_pos] = buffer[addr + i]; - buffer_pos++; + if (addr > offset) { + return absl::InternalError(absl::StrFormat( + "Decompress: Offset for command copy exceeds current position " + "(Offset : %#04x | Pos : %#06x)\n", + addr, offset)); } - offset += 2; // Advance 2 bytes in the ROM - + if (buffer_pos + length >= size) { + size *= 2; + buffer.resize(size); + } + memcpy(buffer.data() + buffer_pos, buffer.data() + addr, length); + buffer_pos += length; + offset += 2; } break; default: { std::cout << absl::StrFormat( @@ -598,12 +580,12 @@ absl::StatusOr ROM::Load2bppGraphics() { Bytes sheet; const uint8_t sheets[] = {113, 114, 218, 219, 220, 221}; - for (int i = 0; i < 6; i++) { - auto offset = GetGraphicsAddress(rom_data_.data(), sheets[i]); + for (const auto& sheet_id : sheets) { + auto offset = GetGraphicsAddress(rom_data_.data(), sheet_id); ASSIGN_OR_RETURN(auto decomp_sheet, Decompress(offset)) - auto converted_sheet = SNES3bppTo8bppSheet(decomp_sheet, 2); - for (int j = 0; j < converted_sheet.size(); ++j) { - sheet.push_back(converted_sheet.at(j)); + auto converted_sheet = SnesTo8bppSheet(decomp_sheet, 2); + for (const auto& each_pixel : converted_sheet) { + sheet.push_back(each_pixel); } } return sheet; @@ -627,8 +609,6 @@ absl::Status ROM::LoadAllGraphicsData() { } bpp3 = true; } else if (i == 113 || i == 114 || i >= 218) { - // auto offset = GetGraphicsAddress(rom_data_.data(), i); - // ASSIGN_OR_RETURN(sheet, Decompress(offset)) bpp3 = false; } else { auto offset = GetGraphicsAddress(rom_data_.data(), i); @@ -637,7 +617,7 @@ absl::Status ROM::LoadAllGraphicsData() { } if (bpp3) { - auto converted_sheet = SNES3bppTo8bppSheet(sheet, 3); + auto converted_sheet = SnesTo8bppSheet(sheet, 3); graphics_bin_[i] = gfx::Bitmap(core::kTilesheetWidth, core::kTilesheetHeight, core::kTilesheetDepth, converted_sheet.data(), 0x1000); @@ -647,15 +627,8 @@ absl::Status ROM::LoadAllGraphicsData() { graphics_buffer_.push_back(graphics_bin_.at(i).GetByte(j)); } } else { - // auto converted_sheet = SNES3bppTo8bppSheet(sheet, 2); - // graphics_bin_[i] = - // gfx::Bitmap(core::kTilesheetWidth, core::kTilesheetHeight, - // core::kTilesheetDepth, converted_sheet.data(), 0x1000); - // graphics_bin_.at(i).CreateTexture(renderer_); - for (int j = 0; j < graphics_bin_.at(0).GetSize(); ++j) { graphics_buffer_.push_back(0xFF); - // graphics_buffer_.push_back(graphics_bin_.at(i).GetByte(j)); } } } diff --git a/src/app/rom.h b/src/app/rom.h index a8beaec6..8f753b28 100644 --- a/src/app/rom.h +++ b/src/app/rom.h @@ -93,7 +93,6 @@ class ROM { void RenderBitmap(gfx::Bitmap* bitmap) const; - auto GetSize() const { return size_; } auto GetTitle() const { return title; } auto GetGraphicsBin() const { return graphics_bin_; } auto GetGraphicsBuffer() const { return graphics_buffer_; } @@ -105,6 +104,7 @@ class ROM { auto begin() { return rom_data_.begin(); } auto end() { return rom_data_.end(); } auto data() { return rom_data_.data(); } + auto size() const { return size_; } uchar& operator[](int i) { if (i > size_) { diff --git a/src/app/zelda3/inventory.cc b/src/app/zelda3/inventory.cc index 96093bdc..b69039cc 100644 --- a/src/app/zelda3/inventory.cc +++ b/src/app/zelda3/inventory.cc @@ -8,22 +8,18 @@ namespace yaze { namespace app { namespace zelda3 { -void Inventory::Create(Bytes& all_gfx) { +void Inventory::Create() { data_.reserve(256 * 256); for (int i = 0; i < 256 * 256; i++) { data_.push_back(0xFF); } - PRINT_IF_ERROR(BuildTileset(all_gfx)) - //tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kInventoryStart))); - - tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kBowItemPos))); - tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kBowItemPos + 0x02))); - tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kBowItemPos + 0x04))); - tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kBowItemPos + 0x08))); - // tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kLampItemPos))); - // tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kLampItemPos + 0x02))); - // tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kLampItemPos + 0x04))); - // tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kLampItemPos + 0x08))); + PRINT_IF_ERROR(BuildTileset()) + for (int i = 0; i < 0x400; i += 0x08) { + tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(i + kBowItemPos))); + tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(i + kBowItemPos + 0x02))); + tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(i + kBowItemPos + 0x04))); + tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(i + kBowItemPos + 0x08))); + } const int offsets[] = {0x00, 0x08, 0x800, 0x808}; auto xx = 0; auto yy = 0; @@ -49,15 +45,15 @@ void Inventory::Create(Bytes& all_gfx) { int source = ypos + xpos + (x + (y * 0x80)); auto destination = xx + yy + offset + (mx + (my * 0x100)); - data_[destination] = (tilesheets_[source] & 0x0F); + data_[destination] = (test_[source] & 0x0F) + tile.palette_ * 0x08; } } if (i == 4) { i = 0; xx += 0x10; - if (xx >= 0x80) { - yy += 0x800; + if (xx >= 0x100) { + yy += 0x1000; xx = 0; } } else { @@ -65,15 +61,24 @@ void Inventory::Create(Bytes& all_gfx) { } } bitmap_.Create(256, 256, 128, data_); - // bitmap_.ApplyPalette(rom_.GetPaletteGroup("hud")[0]); + bitmap_.ApplyPalette(palette_); rom_.RenderBitmap(&bitmap_); } -absl::Status Inventory::BuildTileset(Bytes& all_gfx) { +absl::Status Inventory::BuildTileset() { tilesheets_.reserve(6 * 0x2000); for (int i = 0; i < 6 * 0x2000; i++) tilesheets_.push_back(0xFF); ASSIGN_OR_RETURN(tilesheets_, rom_.Load2bppGraphics()) - tilesheets_bmp_.Create(128, 192 + 96 + 48 - 16, 64, tilesheets_); + Bytes test; + for (int i = 0; i < 0x4000; i++) { + test_.push_back(tilesheets_[i]); + } + for (int i = 0x8000; i < + 0x8000 + 0x2000; i++) { + test_.push_back(tilesheets_[i]); + } + tilesheets_bmp_.Create(128, 0x130, 64, test_); + palette_ = rom_.GetPaletteGroup("hud")[0]; + tilesheets_bmp_.ApplyPalette(palette_); rom_.RenderBitmap(&tilesheets_bmp_); return absl::OkStatus(); } diff --git a/src/app/zelda3/inventory.h b/src/app/zelda3/inventory.h index ed3fa7d3..4b714f8a 100644 --- a/src/app/zelda3/inventory.h +++ b/src/app/zelda3/inventory.h @@ -3,6 +3,7 @@ #include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" +#include "app/gfx/snes_palette.h" #include "app/rom.h" #include "gui/canvas.h" @@ -11,7 +12,6 @@ namespace app { namespace zelda3 { constexpr int kInventoryStart = 0x6564A; -constexpr int kLampItemPos = 0x6F6F9; constexpr int kBowItemPos = 0x6F631; class Inventory { @@ -19,11 +19,12 @@ class Inventory { void SetupROM(ROM& rom) { rom_ = rom; } auto Bitmap() const { return bitmap_; } auto Tilesheet() const { return tilesheets_bmp_; } + auto Palette() const { return palette_; } - void Create(Bytes& all_gfx); + void Create(); private: - absl::Status BuildTileset(Bytes& all_gfx); + absl::Status BuildTileset(); ROM rom_; @@ -31,7 +32,9 @@ class Inventory { gfx::Bitmap bitmap_; Bytes tilesheets_; + Bytes test_; gfx::Bitmap tilesheets_bmp_; + gfx::SNESPalette palette_; gui::Canvas canvas_; std::vector tiles_; diff --git a/src/gui/canvas.cc b/src/gui/canvas.cc index e97f2a25..ccef103a 100644 --- a/src/gui/canvas.cc +++ b/src/gui/canvas.cc @@ -64,6 +64,7 @@ void Canvas::DrawContextMenu() { ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); if (ImGui::BeginPopup("context")) { + ImGui::MenuItem("Show Grid", nullptr, &enable_grid_); if (ImGui::MenuItem("Reset Position", nullptr, false)) { scrolling_.x = 0; scrolling_.y = 0; diff --git a/src/gui/color.cc b/src/gui/color.cc new file mode 100644 index 00000000..22c836a1 --- /dev/null +++ b/src/gui/color.cc @@ -0,0 +1,84 @@ +#include "color.h" + +#include + +#include +#include + +#include "app/gfx/bitmap.h" +#include "app/gfx/snes_palette.h" + +namespace yaze { +namespace gui { +void DisplayPalette(app::gfx::SNESPalette& palette, bool loaded) { + static ImVec4 color = ImVec4(0, 0, 0, 255.f); + ImGuiColorEditFlags misc_flags = ImGuiColorEditFlags_AlphaPreview | + ImGuiColorEditFlags_NoDragDrop | + ImGuiColorEditFlags_NoOptions; + + // Generate a default palette. The palette will persist and can be edited. + static bool init = false; + static ImVec4 saved_palette[32] = {}; + if (loaded && !init) { + for (int n = 0; n < palette.size_; n++) { + saved_palette[n].x = palette.GetColor(n).rgb.x / 255; + saved_palette[n].y = palette.GetColor(n).rgb.y / 255; + saved_palette[n].z = palette.GetColor(n).rgb.z / 255; + saved_palette[n].w = 255; // Alpha + } + init = true; + } + + static ImVec4 backup_color; + ImGui::Text("Current ==>"); + ImGui::SameLine(); + ImGui::Text("Previous"); + + ImGui::ColorButton( + "##current", color, + ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, + ImVec2(60, 40)); + ImGui::SameLine(); + + if (ImGui::ColorButton( + "##previous", backup_color, + ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, + ImVec2(60, 40))) + color = backup_color; + ImGui::Separator(); + +ImGui::BeginGroup(); // Lock X position + ImGui::Text("Palette"); + for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) { + ImGui::PushID(n); + if ((n % 4) != 0) ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); + + ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | + ImGuiColorEditFlags_NoPicker | + ImGuiColorEditFlags_NoTooltip; + if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, + ImVec2(20, 20))) + color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, + color.w); // Preserve alpha! + + if (ImGui::BeginDragDropTarget()) { + if (const ImGuiPayload* payload = + ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) + memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3); + if (const ImGuiPayload* payload = + ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) + memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4); + ImGui::EndDragDropTarget(); + } + + ImGui::PopID(); + } + ImGui::EndGroup(); + ImGui::SameLine(); + + ImGui::ColorPicker4("##picker", (float*)&color, + misc_flags | ImGuiColorEditFlags_NoSidePreview | + ImGuiColorEditFlags_NoSmallPreview); +} +} // namespace gui +} // namespace yaze \ No newline at end of file diff --git a/src/gui/color.h b/src/gui/color.h new file mode 100644 index 00000000..fc9c5bc4 --- /dev/null +++ b/src/gui/color.h @@ -0,0 +1,20 @@ +#ifndef YAZE_GUI_COLOR_H +#define YAZE_GUI_COLOR_H + +#include + +#include +#include + +#include "app/gfx/bitmap.h" +#include "app/gfx/snes_palette.h" + +namespace yaze { +namespace gui { + +void DisplayPalette(app::gfx::SNESPalette& palette, bool loaded); + +} // namespace gui +} // namespace yaze + +#endif \ No newline at end of file diff --git a/test/asm_test.cc b/test/asm_test.cc index 6ce8cfcc..e9212e8e 100644 --- a/test/asm_test.cc +++ b/test/asm_test.cc @@ -30,7 +30,7 @@ using ::testing::Return; class MockScript : public Script { public: MOCK_METHOD(absl::Status, ApplyPatchToROM, (ROM & rom)); - MOCK_METHOD(absl::Status, GenerateMosaicChangeAssembly, + MOCK_METHOD(absl::Status, PatchOverworldMosaic, (ROM & rom, char mosaic_tiles[yaze::app::core::kNumOverworldMaps], int routine_offset, int hook_offset)); }; @@ -40,15 +40,15 @@ TEST(ASMTest, ApplyMosaicChangePatchOk) { MockScript script; char mosaic_tiles[yaze::app::core::kNumOverworldMaps]; - EXPECT_CALL(script, GenerateMosaicChangeAssembly(_, Eq(mosaic_tiles), - Eq(0x1301D0 + 0x138000), 0)) + EXPECT_CALL(script, PatchOverworldMosaic(_, Eq(mosaic_tiles), + Eq(0x1301D0 + 0x138000), 0)) .WillOnce(Return(absl::OkStatus())); EXPECT_CALL(script, ApplyPatchToROM(_)).WillOnce(Return(absl::OkStatus())); - EXPECT_THAT(script.GenerateMosaicChangeAssembly(rom, mosaic_tiles, - 0x1301D0 + 0x138000, 0), - absl::OkStatus()); + EXPECT_THAT( + script.PatchOverworldMosaic(rom, mosaic_tiles, 0x1301D0 + 0x138000, 0), + absl::OkStatus()); EXPECT_THAT(script.ApplyPatchToROM(rom), absl::OkStatus()); }