From df8443152b67c11bfc64bcfd504b44275d1cb3cb Mon Sep 17 00:00:00 2001 From: scawful Date: Tue, 18 Jul 2023 21:55:23 -0400 Subject: [PATCH] Add CgxViewer, update GraphicsEditor --- src/CMakeLists.txt | 6 ++ src/app/core/constants.h | 17 ++++- src/app/editor/graphics_editor.cc | 93 +++++++++++++++--------- src/app/editor/graphics_editor.h | 10 ++- src/app/gfx/snes_palette.cc | 20 ++++++ src/app/gfx/snes_palette.h | 4 ++ src/app/rom.cc | 2 + src/app/viewer/cgx_viewer.cc | 113 ++++++++++++++++++++++++++++++ src/app/viewer/cgx_viewer.h | 41 +++++++++++ test/asm_test.cc | 67 ------------------ 10 files changed, 271 insertions(+), 102 deletions(-) create mode 100644 src/app/viewer/cgx_viewer.cc create mode 100644 src/app/viewer/cgx_viewer.h delete mode 100644 test/asm_test.cc diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 15d45bd7..5f2c2e7f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -44,6 +44,11 @@ set( app/gui/color.cc ) +set( + YAZE_VIEWER_SRC + app/viewer/cgx_viewer.cc +) + # executable creation --------------------------------------------------------- add_executable( @@ -55,6 +60,7 @@ add_executable( ${YAZE_APP_GFX_SRC} ${YAZE_APP_ZELDA3_SRC} ${YAZE_GUI_SRC} + ${YAZE_VIEWER_SRC} # ${ASAR_STATIC_SRC} # ${SNES_SPC_SOURCES} ${IMGUI_SRC} diff --git a/src/app/core/constants.h b/src/app/core/constants.h index a8a84372..71baa648 100644 --- a/src/app/core/constants.h +++ b/src/app/core/constants.h @@ -33,6 +33,19 @@ ImGui::TableNextColumn(); \ ImGui::Text(w); +#define BEGIN_TABLE(l, n, f) if (ImGui::BeginTable(l, n, f, ImVec2(0, 0))) { +#define SETUP_COLUMN(l) ImGui::TableSetupColumn(l); + +#define TABLE_HEADERS() \ + ImGui::TableHeadersRow(); \ + ImGui::TableNextRow(); + +#define NEXT_COLUMN() ImGui::TableNextColumn(); + +#define END_TABLE() \ + ImGui::EndTable(); \ + } + #define PRINT_IF_ERROR(expression) \ { \ auto error = expression; \ @@ -66,7 +79,7 @@ #define APPEND_NUMBER_INNER(expression, number) expression##number #define TEXT_WITH_SEPARATOR(text) \ - ImGui::Text(text); \ + ImGui::Text(text); \ ImGui::Separator(); using ushort = unsigned short; @@ -501,7 +514,7 @@ constexpr int customAreaSpecificBGPalette = constexpr int customAreaSpecificBGASM = 0x140150; constexpr int customAreaSpecificBGEnabled = 0x140140; // 1 byte, not 0 if enabled - + // ============================================================================ // Dungeon Map Related Variables // ============================================================================ diff --git a/src/app/editor/graphics_editor.cc b/src/app/editor/graphics_editor.cc index fc3563e9..1661ddaa 100644 --- a/src/app/editor/graphics_editor.cc +++ b/src/app/editor/graphics_editor.cc @@ -19,31 +19,37 @@ namespace app { namespace editor { absl::Status GraphicsEditor::Update() { - if (ImGui::BeginTable("#gfxEditTable", 2, gfx_edit_flags, ImVec2(0, 0))) { - ImGui::TableSetupColumn("Bin Importer", ImGuiTableColumnFlags_WidthStretch, - ImGui::GetContentRegionAvail().x); - ImGui::TableSetupColumn("Graphics Manager"); - ImGui::TableHeadersRow(); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - RETURN_IF_ERROR(DrawImport()) + BEGIN_TABLE("#gfxEditTable", 2, gfx_edit_flags) + SETUP_COLUMN("Bin Importer") + SETUP_COLUMN("Graphics Manager") + TABLE_HEADERS() + NEXT_COLUMN() - ImGui::TableNextColumn(); + TAB_BAR("##GfxTabBar") + TAB_ITEM("File Import") + RETURN_IF_ERROR(DrawFileImport()) + END_TAB_ITEM() + TAB_ITEM("Clipboard Import") + RETURN_IF_ERROR(DrawClipboardImport()) + END_TAB_ITEM() + END_TAB_BAR() + ImGui::Text("Graphics"); + ImGui::Separator(); + RETURN_IF_ERROR(DrawDecompressedData()) - ImGui::EndTable(); - } + NEXT_COLUMN() + RETURN_IF_ERROR(DrawMemoryEditor()) + END_TABLE() return absl::OkStatus(); } -absl::Status GraphicsEditor::DrawImport() { +absl::Status GraphicsEditor::DrawFileImport() { static int size = 0; - static char filePath[256] = ""; - static bool open = false; ImGui::SetNextItemWidth(350.f); - ImGui::InputText("File", filePath, sizeof(filePath)); - + ImGui::InputText("File", file_path_, sizeof(file_path_)); + ImGui::SameLine(); // Open the file dialog when the user clicks the "Browse" button if (ImGui::Button("Browse")) { ImGuiFileDialog::Instance()->OpenDialog("ImportDlgKey", "Choose File", @@ -52,35 +58,33 @@ absl::Status GraphicsEditor::DrawImport() { // Draw the file dialog if (ImGuiFileDialog::Instance()->Display("ImportDlgKey")) { - // If the user made a selection, copy the filename to the filePath buffer + // If the user made a selection, copy the filename to the file_path_ buffer if (ImGuiFileDialog::Instance()->IsOk()) { - strncpy(filePath, ImGuiFileDialog::Instance()->GetFilePathName().c_str(), - sizeof(filePath)); - RETURN_IF_ERROR(temp_rom_.LoadFromFile(filePath)) - open = true; + strncpy(file_path_, + ImGuiFileDialog::Instance()->GetFilePathName().c_str(), + sizeof(file_path_)); + RETURN_IF_ERROR(temp_rom_.LoadFromFile(file_path_)) + is_open_ = true; } // Close the modal ImGuiFileDialog::Instance()->Close(); } - if (open) { - static MemoryEditor mem_edit; - mem_edit.DrawWindow(filePath, (void *)&temp_rom_, temp_rom_.size()); - } - gui::InputHex("Offset", ¤t_offset_); gui::InputHex("Size ", &size); gui::InputHex("Palette ", ¤t_palette_); - if (ImGui::Button("Super Donkey")) { + if (ImGui::Button("Super Donkey Offsets")) { current_offset_ = 0x98219; size = 0x30000; } + ImGui::SameLine(); + if (ImGui::Button("Import")) { - if (strlen(filePath) > 0) { - // Add your importing code here, using filePath and offset as parameters + if (strlen(file_path_) > 0) { + // Add your importing code here, using file_path_ and offset as parameters RETURN_IF_ERROR(DecompressImportData(size)) } else { // Show an error message if no file has been selected @@ -88,6 +92,32 @@ absl::Status GraphicsEditor::DrawImport() { } } + return absl::OkStatus(); +} + +absl::Status GraphicsEditor::DrawClipboardImport() { + static Bytes clipboard_data; + + if (!is_open_) { + clipboard_data.resize(0x1000); + for (int i = 0; i < 0x1000; i++) clipboard_data.push_back(0x00); + RETURN_IF_ERROR(temp_rom_.LoadFromBytes(clipboard_data)) + is_open_ = true; + } + + return absl::OkStatus(); +} + +absl::Status GraphicsEditor::DrawMemoryEditor() { + std::string title = "Memory Editor"; + if (is_open_) { + static MemoryEditor mem_edit; + mem_edit.DrawWindow(title.data(), (void *)&temp_rom_, temp_rom_.size()); + } + return absl::OkStatus(); +} + +absl::Status GraphicsEditor::DrawDecompressedData() { if (ImGuiID child_id = ImGui::GetID((void *)(intptr_t)2); ImGui::BeginChild(child_id, ImGui::GetContentRegionAvail(), true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) { @@ -99,17 +129,16 @@ absl::Status GraphicsEditor::DrawImport() { import_canvas_.DrawOverlay(); } ImGui::EndChild(); - return absl::OkStatus(); } absl::Status GraphicsEditor::DecompressImportData(int size) { ASSIGN_OR_RETURN(import_data_, temp_rom_.Decompress(current_offset_, size)) - std::cout << "Size of import data" << import_data_.size() << std::endl; + std::cout << "Size of import data " << import_data_.size() << std::endl; Bytes new_sheet; bitmap_.Create(core::kTilesheetWidth, 0x2000, core::kTilesheetDepth, - import_data_.data(), 0x1000); + import_data_.data(), size); if (rom_.isLoaded()) { auto palette_group = rom_.GetPaletteGroup("ow_main"); diff --git a/src/app/editor/graphics_editor.h b/src/app/editor/graphics_editor.h index ae94c905..4844a34f 100644 --- a/src/app/editor/graphics_editor.h +++ b/src/app/editor/graphics_editor.h @@ -46,13 +46,20 @@ class GraphicsEditor { void SetupROM(ROM &rom) { rom_ = rom; } private: - absl::Status DrawImport(); + absl::Status DrawFileImport(); + absl::Status DrawClipboardImport(); + absl::Status DrawMemoryEditor(); + absl::Status DrawDecompressedData(); + absl::Status DecompressImportData(int size); + int current_offset_ = 0; int current_size_ = 0; int current_palette_ = 0; bool gfx_loaded_ = false; + bool is_open_ = false; + char file_path_[256]; ROM rom_; ROM temp_rom_; @@ -65,6 +72,7 @@ class GraphicsEditor { PaletteEditor palette_editor_; gfx::SNESPalette palette_; + MemoryEditor memory_editor_; ImGuiTableFlags gfx_edit_flags = ImGuiTableFlags_Reorderable | ImGuiTableFlags_Resizable | diff --git a/src/app/gfx/snes_palette.cc b/src/app/gfx/snes_palette.cc index c69a03e0..06bf475e 100644 --- a/src/app/gfx/snes_palette.cc +++ b/src/app/gfx/snes_palette.cc @@ -60,6 +60,26 @@ char* Convert(const snes_palette pal) { return toret; } +SNESColor GetCgxColor(short color) { + ImVec4 rgb; + rgb.x = (color & 0x1F) * 8; + rgb.y = ((color & 0x3E0) >> 5) * 8; + rgb.z = ((color & 0x7C00) >> 10) * 8; + SNESColor toret; + toret.setRgb(rgb); + return toret; +} + +std::vector GetColFileData(uchar* data) { + std::vector colors; + + for (int i = 0; i < 512; i += 2) { + colors[i / 2] = GetCgxColor((short)((data[i + 1] << 8) + data[i])); + } + + return colors; +} + // ============================================================================ SNESColor::SNESColor() : rgb(ImVec4(0.f, 0.f, 0.f, 0.f)) {} diff --git a/src/app/gfx/snes_palette.h b/src/app/gfx/snes_palette.h index bb38b394..90bb0407 100644 --- a/src/app/gfx/snes_palette.h +++ b/src/app/gfx/snes_palette.h @@ -66,6 +66,10 @@ struct SNESColor { ImVec4 rgb; }; +SNESColor GetCgxColor(short color); + +std::vector GetColFileData(uchar* data); + class SNESPalette { public: SNESPalette() = default; diff --git a/src/app/rom.cc b/src/app/rom.cc index 28de2fb0..256af9c0 100644 --- a/src/app/rom.cc +++ b/src/app/rom.cc @@ -643,6 +643,8 @@ absl::Status ROM::LoadFromBytes(const Bytes& data) { "Could not load ROM: parameter `data` is empty."); } rom_data_ = data; + size_ = data.size(); + is_loaded_ = true; return absl::OkStatus(); } diff --git a/src/app/viewer/cgx_viewer.cc b/src/app/viewer/cgx_viewer.cc new file mode 100644 index 00000000..7a9c5f7d --- /dev/null +++ b/src/app/viewer/cgx_viewer.cc @@ -0,0 +1,113 @@ +#include "cgx_viewer.h" + +#include +#include +#include + +#include "app/gfx/bitmap.h" +#include "app/gfx/snes_palette.h" +#include "app/gfx/snes_tile.h" + +namespace yaze { +namespace app { +namespace viewer { + +void CgxViewer::Update() { + static int current_bpp = 1; + // ImGui::Combo("BPP", current_bpp, "0\0 1\0 2\0 3\0", 4, 4); + LoadColFile(); + LoadGfx(current_bpp); + LoadScr(); +} + +void CgxViewer::LoadColFile() { + uchar data[512]; + + std::vector colors; + for (int i = 0; i < 512; i += 2) { + colors[i / 2] = gfx::GetCgxColor((short)((data[i + 1] << 8) + data[i])); + } +} + +void CgxViewer::LoadCgx(std::string pathfile) { + unsigned char* ptr = rawData.data(); + + for (int i = 0; i < 0x40000; i++) { + ptr[i] = 0; + rawData[i] = 0; + } + + std::ifstream fs(pathfile, std::ios::binary); + std::vector data((std::istreambuf_iterator(fs)), + std::istreambuf_iterator()); + fs.close(); + + int matchingPos = -1; + bool matched = false; + for (int i = 0; i < data.size(); i++) { + if (matched) { + break; + } + rawData[i] = data[i]; + for (int j = 0; j < matchBytes.size(); j++) { + if (data[i + j] == matchBytes[j]) { + if (j == matchBytes.size() - 1) { + matchingPos = i; + matched = true; + break; + } + } else { + break; + } + } + } + + char buffer[10]; + sprintf(buffer, "%X4", matchingPos); + label1_text = "CGX In Folder L : " + std::string(buffer); + LoadGfx(current_selection_); +} + +struct GFX_Class { + unsigned char* indexedPointer; +} GFX; +struct PictureBox_Class { + void (*Refresh)(); +} pictureBox1; + +void CgxViewer::LoadGfx(int comboBpp) { + if (comboBpp == 0) { + bpp_ = 4; + } else if (comboBpp == 1) { + bpp_ = 2; + } else if (comboBpp == 2) { + bpp_ = 8; + } else if (comboBpp == 3) { + bpp_ = 40; + unsigned char* ptr = GFX.indexedPointer; + for (int i = 0; i < rawData.size(); i++) { + ptr[i] = rawData[i]; + } + RefreshPalettes(); + pictureBox1.Refresh(); + return; + } + + unsigned char* ptr = GFX.indexedPointer; + Bytes rawBytes; // rawData.data() + std::vector dd = gfx::SnesTo8bppSheet(rawBytes, bpp_); + for (int i = 0; i < dd.size(); i++) { + ptr[i] = dd[i]; + } + + RefreshPalettes(); + pictureBox1.Refresh(); +} + +void CgxViewer::LoadScr() {} + +void CgxViewer::RefreshPalettes() {} + +} // namespace viewer +} // namespace app +} // namespace yaze \ No newline at end of file diff --git a/src/app/viewer/cgx_viewer.h b/src/app/viewer/cgx_viewer.h new file mode 100644 index 00000000..c3c91638 --- /dev/null +++ b/src/app/viewer/cgx_viewer.h @@ -0,0 +1,41 @@ +#ifndef YAZE_APP_VIEWER_CGX_VIEWER_H +#define YAZE_APP_VIEWER_CGX_VIEWER_H +#include +#include +#include + +#include "app/gfx/bitmap.h" +#include "app/gfx/snes_palette.h" +#include "app/gfx/snes_tile.h" +#include "app/rom.h" + +namespace yaze { +namespace app { +namespace viewer { + +class CgxViewer { + public: + void Update(); + + private: + void LoadColFile(); + + void LoadCgx(std::string pathfile); + void LoadGfx(int comboBpp); + void LoadScr(); + + void RefreshPalettes(); + + std::vector matchBytes; // Assuming it's a vector of bytes. + std::string label1_text; + + int bpp_; + int current_selection_; + ROM rawData; +}; + +} // namespace viewer +} // namespace app +} // namespace yaze + +#endif // YAZE_APP_VIEWER_CGX_VIEWER_H \ No newline at end of file diff --git a/test/asm_test.cc b/test/asm_test.cc deleted file mode 100644 index 9308895a..00000000 --- a/test/asm_test.cc +++ /dev/null @@ -1,67 +0,0 @@ -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/string_view.h" -#include "app/asm/script.h" -#include "app/core/constants.h" -#include "app/rom.h" - -namespace yaze_test { -namespace asm_test { - -using yaze::app::ROM; -using yaze::app::snes_asm::Script; - -using ::testing::_; -using ::testing::ElementsAreArray; -using ::testing::Eq; -using ::testing::Return; - -class MockScript : public Script { - public: - MOCK_METHOD(absl::Status, ApplyPatchToROM, (ROM & rom)); - MOCK_METHOD(absl::Status, PatchOverworldMosaic, - (ROM & rom, char mosaic_tiles[yaze::app::core::kNumOverworldMaps], - int routine_offset, int hook_offset)); -}; - -TEST(ASMTest, ApplyMosaicChangePatchOk) { - ROM rom; - MockScript script; - char mosaic_tiles[yaze::app::core::kNumOverworldMaps]; - - 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.PatchOverworldMosaic(rom, mosaic_tiles, 0x1301D0 + 0x138000, 0), - absl::OkStatus()); - EXPECT_THAT(script.ApplyPatchToROM(rom), absl::OkStatus()); -} - -TEST(ASMTest, NoPatchLoadedError) { - ROM rom; - MockScript script; - EXPECT_CALL(script, ApplyPatchToROM(_)) - .WillOnce(Return(absl::InvalidArgumentError("No patch loaded!"))); - - EXPECT_THAT(script.ApplyPatchToROM(rom), - absl::InvalidArgumentError("No patch loaded!")); -} - -} // namespace asm_test -} // namespace yaze_test \ No newline at end of file