From 7d0b09a5891de77ebbcf957f61601f9d134893da Mon Sep 17 00:00:00 2001 From: Justin Scofield <47263509+scawful@users.noreply.github.com> Date: Thu, 3 Aug 2023 21:09:27 -0400 Subject: [PATCH] Add SelectablePalettePipeline for updating palette --- src/app/core/pipeline.cc | 47 ++++++++++++++++++++++++---- src/app/core/pipeline.h | 7 +++-- src/app/editor/graphics_editor.cc | 49 ++++++++++++++++-------------- src/app/editor/graphics_editor.h | 2 +- src/app/editor/master_editor.cc | 6 ++++ src/app/editor/overworld_editor.cc | 8 ++--- src/app/gfx/bitmap.cc | 14 +++++++++ src/app/gfx/bitmap.h | 2 ++ src/app/gfx/snes_palette.cc | 14 +++++++++ src/app/gfx/snes_palette.h | 2 ++ src/app/gui/style.cc | 2 +- 11 files changed, 116 insertions(+), 37 deletions(-) diff --git a/src/app/core/pipeline.cc b/src/app/core/pipeline.cc index bb134f33..19412370 100644 --- a/src/app/core/pipeline.cc +++ b/src/app/core/pipeline.cc @@ -19,6 +19,33 @@ namespace yaze { namespace app { namespace core { +void SelectablePalettePipeline(uint64_t& palette_id, bool& refresh_graphics, + gfx::SNESPalette& palette) { + if (ImGuiID child_id = ImGui::GetID((void*)(intptr_t)100); + ImGui::BeginChild(child_id, ImGui::GetContentRegionAvail(), true, + ImGuiWindowFlags_AlwaysVerticalScrollbar)) { + ImGui::BeginGroup(); // Lock X position + ImGui::Text("Palette"); + for (int n = 0; n < palette.size(); n++) { + ImGui::PushID(n); + if ((n % 8) != 0) ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); + + if (ImGui::ColorButton("##palette", palette[n].RGB(), + ImGuiColorEditFlags_NoAlpha | + ImGuiColorEditFlags_NoPicker | + ImGuiColorEditFlags_NoTooltip, + ImVec2(20, 20))) { + palette_id = n / 8; + refresh_graphics = true; + } + + ImGui::PopID(); + } + ImGui::EndGroup(); + } + ImGui::EndChild(); +} + void GraphicsBinCanvasPipeline(int width, int height, int tile_size, int num_sheets_to_load, int canvas_id, bool is_loaded, gfx::BitmapTable& graphics_bin) { @@ -56,21 +83,29 @@ void ButtonPipe(absl::string_view button_text, std::function callback) { } } -void BitmapCanvasPipeline(int width, int height, int tile_size, int canvas_id, - bool is_loaded, gfx::Bitmap& bitmap) { +void BitmapCanvasPipeline(int width, int height, int tile_size, bool is_loaded, + gfx::Bitmap& bitmap, bool scrollbar, int canvas_id) { gui::Canvas canvas; - if (ImGuiID child_id = ImGui::GetID((void*)(intptr_t)canvas_id); - ImGui::BeginChild(child_id, ImGui::GetContentRegionAvail(), true, - ImGuiWindowFlags_AlwaysVerticalScrollbar)) { + auto draw_canvas = [&]() { canvas.DrawBackground(ImVec2(width + 1, height + 1)); canvas.DrawContextMenu(); canvas.DrawBitmap(bitmap, 2, is_loaded); canvas.DrawTileSelector(tile_size); canvas.DrawGrid(tile_size); canvas.DrawOverlay(); + }; + + if (scrollbar) { + if (ImGuiID child_id = ImGui::GetID((void*)(intptr_t)canvas_id); + ImGui::BeginChild(child_id, ImGui::GetContentRegionAvail(), true, + ImGuiWindowFlags_AlwaysVerticalScrollbar)) { + draw_canvas(); + } + ImGui::EndChild(); + } else { + draw_canvas(); } - ImGui::EndChild(); } void BuildAndRenderBitmapPipeline(int width, int height, int depth, Bytes data, diff --git a/src/app/core/pipeline.h b/src/app/core/pipeline.h index c602f70f..70a5f497 100644 --- a/src/app/core/pipeline.h +++ b/src/app/core/pipeline.h @@ -19,14 +19,17 @@ namespace yaze { namespace app { namespace core { +void SelectablePalettePipeline(uint64_t& palette_id, bool& refresh_graphics, + gfx::SNESPalette& palette); + void GraphicsBinCanvasPipeline(int width, int height, int tile_size, int num_sheets_to_load, int canvas_id, bool is_loaded, gfx::BitmapTable& graphics_bin); void ButtonPipe(absl::string_view button_text, std::function callback); -void BitmapCanvasPipeline(int width, int height, int tile_size, int canvas_id, - bool is_loaded, gfx::Bitmap& bitmap); +void BitmapCanvasPipeline(int width, int height, int tile_size, bool is_loaded, + gfx::Bitmap& bitmap, bool scrollbar, int canvas_id); void BuildAndRenderBitmapPipeline(int width, int height, int depth, Bytes data, ROM& z3_rom, gfx::Bitmap& bitmap, diff --git a/src/app/editor/graphics_editor.cc b/src/app/editor/graphics_editor.cc index 35cd9d66..8fabd06d 100644 --- a/src/app/editor/graphics_editor.cc +++ b/src/app/editor/graphics_editor.cc @@ -33,7 +33,8 @@ absl::Status GraphicsEditor::Update() { BEGIN_TABLE("#gfxEditTable", 4, kGfxEditFlags) SETUP_COLUMN("Graphics (BIN, CGX, SCR)") SETUP_COLUMN("Palette (COL)") - SETUP_COLUMN("Maps and Animations (SCR, PNL)") + ImGui::TableSetupColumn("Maps and Animations (SCR, PNL)", + ImGuiTableColumnFlags_WidthFixed); SETUP_COLUMN("Preview") TABLE_HEADERS() NEXT_COLUMN() @@ -47,15 +48,30 @@ absl::Status GraphicsEditor::Update() { status_ = DrawPaletteControls(); NEXT_COLUMN() - core::BitmapCanvasPipeline(0x200, 0x200, 0x20, 6, scr_loaded_, cgx_bitmap_); + core::BitmapCanvasPipeline(0x200, 0x200, 0x20, scr_loaded_, cgx_bitmap_, + false, 0); NEXT_COLUMN() if (super_donkey_) { - status_ = DrawGraphicsBin(); + if (refresh_graphics_) { + for (int i = 0; i < graphics_bin_.size(); i++) { + graphics_bin_[i].ApplyPalette( + col_file_palette_group_[current_palette_index_]); + rom_.UpdateBitmap(&graphics_bin_[i]); + } + refresh_graphics_ = false; + } + // Load the full graphics space from `super_donkey_1.bin` + core::GraphicsBinCanvasPipeline(0x100, 0x40, 0x20, num_sheets_to_load_, 3, + super_donkey_, graphics_bin_); } else if (cgx_loaded_ && col_file_) { - core::BitmapCanvasPipeline(0x100, 16384, 0x20, 5, cgx_loaded_, cgx_bitmap_); + // Load the CGX graphics + core::BitmapCanvasPipeline(0x100, 16384, 0x20, cgx_loaded_, cgx_bitmap_, + true, 5); } else { - core::BitmapCanvasPipeline(0x100, 16384, 0x20, 2, gfx_loaded_, bitmap_); + // Load the BIN/Clipboard Graphics + core::BitmapCanvasPipeline(0x100, 16384, 0x20, gfx_loaded_, bitmap_, true, + 2); } END_TABLE() @@ -170,15 +186,7 @@ absl::Status GraphicsEditor::DrawPaletteControls() { if (col_file_palette_group_.size() != 0) { col_file_palette_group_.Clear(); } - for (int i = 0; i < col_data_.size(); i += 8) { - // Extract 8 colors from the col_data_ and make them into a palette - gfx::SNESPalette palette; - for (int j = 0; j < 8; j++) { - palette.AddColor(col_data_[i + j]); - } - // color.AddColor() - col_file_palette_group_.AddPalette(palette); - } + col_file_palette_group_ = gfx::CreatePaletteGroupFromColFile(col_data_); col_file_palette_ = gfx::SNESPalette(col_data_); col_file_ = true; is_open_ = true; @@ -195,7 +203,8 @@ absl::Status GraphicsEditor::DrawPaletteControls() { } if (col_file_palette_.size() != 0) { - palette_editor_.DrawPortablePalette(col_file_palette_); + core::SelectablePalettePipeline(current_palette_index_, refresh_graphics_, + col_file_palette_); } return absl::OkStatus(); @@ -257,12 +266,6 @@ absl::Status GraphicsEditor::DrawMemoryEditor() { return absl::OkStatus(); } -absl::Status GraphicsEditor::DrawGraphicsBin() { - core::GraphicsBinCanvasPipeline(0x100, 0x40, 0x20, num_sheets_to_load_, 3, - super_donkey_, graphics_bin_); - return absl::OkStatus(); -} - absl::Status GraphicsEditor::DecompressImportData(int size) { ASSIGN_OR_RETURN(import_data_, gfx::lc_lz2::DecompressV2( temp_rom_.data(), current_offset_, size)) @@ -298,7 +301,7 @@ absl::Status GraphicsEditor::DecompressSuperDonkey() { auto converted_sheet = gfx::SnesTo8bppSheet(decompressed_data, 3); graphics_bin_[i] = gfx::Bitmap(core::kTilesheetWidth, core::kTilesheetHeight, - core::kTilesheetDepth, converted_sheet.data(), 0x1000); + core::kTilesheetDepth, converted_sheet); if (col_file_) { graphics_bin_[i].ApplyPalette( col_file_palette_group_[current_palette_index_]); @@ -323,7 +326,7 @@ absl::Status GraphicsEditor::DecompressSuperDonkey() { auto converted_sheet = gfx::SnesTo8bppSheet(decompressed_data, 3); graphics_bin_[i] = gfx::Bitmap(core::kTilesheetWidth, core::kTilesheetHeight, - core::kTilesheetDepth, converted_sheet.data(), 0x1000); + core::kTilesheetDepth, converted_sheet); if (col_file_) { graphics_bin_[i].ApplyPalette( col_file_palette_group_[current_palette_index_]); diff --git a/src/app/editor/graphics_editor.h b/src/app/editor/graphics_editor.h index e391e4d3..3224ae0f 100644 --- a/src/app/editor/graphics_editor.h +++ b/src/app/editor/graphics_editor.h @@ -73,7 +73,6 @@ class GraphicsEditor { absl::Status DrawClipboardImport(); absl::Status DrawExperimentalFeatures(); absl::Status DrawMemoryEditor(); - absl::Status DrawGraphicsBin(); absl::Status DecompressImportData(int size); @@ -91,6 +90,7 @@ class GraphicsEditor { uint64_t clipboard_offset_ = 0; uint64_t clipboard_size_ = 0; + bool refresh_graphics_ = false; bool open_memory_editor_ = false; bool gfx_loaded_ = false; bool is_open_ = false; diff --git a/src/app/editor/master_editor.cc b/src/app/editor/master_editor.cc index aaf3361b..c5ca22e1 100644 --- a/src/app/editor/master_editor.cc +++ b/src/app/editor/master_editor.cc @@ -301,8 +301,14 @@ void MasterEditor::DrawHelpMenu() { if (open_rom_help) ImGui::OpenPopup("Open a ROM"); if (ImGui::BeginPopupModal("Open a ROM", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::Text("File -> Open"); + ImGui::Text("Select a ROM file to open"); + ImGui::Text("Supported ROMs:"); ImGui::Text("The Legend of Zelda: A Link to the Past"); ImGui::Text("US Version 1.0"); + ImGui::Separator(); + ImGui::Text("Must remove header before opening"); + ImGui::Text("Header is 0x200 bytes of data at the beginning of the ROM"); if (ImGui::Button("Close", gui::kDefaultModalSize)) { open_rom_help = false; diff --git a/src/app/editor/overworld_editor.cc b/src/app/editor/overworld_editor.cc index 2d4be056..5dd217e1 100644 --- a/src/app/editor/overworld_editor.cc +++ b/src/app/editor/overworld_editor.cc @@ -263,8 +263,8 @@ void OverworldEditor::DrawTileSelector() { if (ImGui::BeginTabBar(kTileSelectorTab.data(), ImGuiTabBarFlags_FittingPolicyScroll)) { if (ImGui::BeginTabItem("Tile16")) { - core::BitmapCanvasPipeline(0x100, (8192 * 2), 0x20, 1, - map_blockset_loaded_, tile16_blockset_bmp_); + core::BitmapCanvasPipeline(0x100, (8192 * 2), 0x20, map_blockset_loaded_, + tile16_blockset_bmp_, true, 1); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Tile8")) { @@ -277,8 +277,8 @@ void OverworldEditor::DrawTileSelector() { ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Area Graphics")) { - core::BitmapCanvasPipeline(256, 0x10 * 0x40, 0x20, 3, - overworld_.isLoaded(), current_gfx_bmp_); + core::BitmapCanvasPipeline(256, 0x10 * 0x40, 0x20, overworld_.isLoaded(), + current_gfx_bmp_, true, 3); ImGui::EndTabItem(); } ImGui::EndTabBar(); diff --git a/src/app/gfx/bitmap.cc b/src/app/gfx/bitmap.cc index c4ab757b..e6480a81 100644 --- a/src/app/gfx/bitmap.cc +++ b/src/app/gfx/bitmap.cc @@ -37,6 +37,10 @@ Bitmap::Bitmap(int width, int height, int depth, uchar *data, int data_size) { Create(width, height, depth, data, data_size); } +Bitmap::Bitmap(int width, int height, int depth, Bytes data) { + Create(width, height, depth, data); +} + // Pass raw pixel data directly to the surface void Bitmap::Create(int width, int height, int depth, uchar *data) { active_ = true; @@ -112,9 +116,18 @@ void Bitmap::CreateTexture(std::shared_ptr renderer) { SDL_Texture_Deleter{}}; } +void Bitmap::UpdateTexture(std::shared_ptr renderer) { + SDL_DestroyTexture(texture_.get()); + texture_ = nullptr; + texture_ = std::shared_ptr{ + SDL_CreateTextureFromSurface(renderer.get(), surface_.get()), + SDL_Texture_Deleter{}}; +} + // Convert SNESPalette to SDL_Palette for surface. void Bitmap::ApplyPalette(const SNESPalette &palette) { palette_ = palette; + SDL_UnlockSurface(surface_.get()); for (int i = 0; i < palette.size_; ++i) { if (palette.GetColor(i).transparent) { surface_->format->palette->colors[i].r = 0; @@ -128,6 +141,7 @@ void Bitmap::ApplyPalette(const SNESPalette &palette) { surface_->format->palette->colors[i].a = palette.GetColor(i).rgb.w; } } + SDL_LockSurface(surface_.get()); } } // namespace gfx diff --git a/src/app/gfx/bitmap.h b/src/app/gfx/bitmap.h index 106a411a..ad209bb5 100644 --- a/src/app/gfx/bitmap.h +++ b/src/app/gfx/bitmap.h @@ -22,6 +22,7 @@ class Bitmap { Bitmap(int width, int height, int depth, uchar *data); Bitmap(int width, int height, int depth, int data_size); Bitmap(int width, int height, int depth, uchar *data, int data_size); + Bitmap(int width, int height, int depth, Bytes data); void Create(int width, int height, int depth, uchar *data); void Create(int width, int height, int depth, int data_size); @@ -31,6 +32,7 @@ class Bitmap { void Apply(Bytes data); void CreateTexture(std::shared_ptr renderer); + void UpdateTexture(std::shared_ptr renderer); void ApplyPalette(const SNESPalette &palette); diff --git a/src/app/gfx/snes_palette.cc b/src/app/gfx/snes_palette.cc index bc529ecf..d52d2284 100644 --- a/src/app/gfx/snes_palette.cc +++ b/src/app/gfx/snes_palette.cc @@ -214,6 +214,20 @@ SDL_Palette* SNESPalette::GetSDL_Palette() { PaletteGroup::PaletteGroup(uint8_t mSize) : size_(mSize) {} +PaletteGroup CreatePaletteGroupFromColFile( + std::vector& palette_rows) { + PaletteGroup toret; + + for (int i = 0; i < palette_rows.size(); i += 8) { + SNESPalette palette; + for (int j = 0; j < 8; j++) { + palette.AddColor(palette_rows[i + j]); + } + toret.AddPalette(palette); + } + return toret; +} + } // namespace gfx } // namespace app } // namespace yaze \ No newline at end of file diff --git a/src/app/gfx/snes_palette.h b/src/app/gfx/snes_palette.h index 704423dc..dd2e0840 100644 --- a/src/app/gfx/snes_palette.h +++ b/src/app/gfx/snes_palette.h @@ -156,6 +156,8 @@ struct PaletteGroup { std::vector palettes; }; +PaletteGroup CreatePaletteGroupFromColFile(std::vector& colors); + } // namespace gfx } // namespace app } // namespace yaze diff --git a/src/app/gui/style.cc b/src/app/gui/style.cc index 4b8c57a2..f49d58d7 100644 --- a/src/app/gui/style.cc +++ b/src/app/gui/style.cc @@ -17,7 +17,7 @@ void ColorsYaze() { ImVec4 *colors = style->Colors; style->WindowPadding = ImVec2(10.f, 10.f); - style->FramePadding = ImVec2(10.f, 3.f); + style->FramePadding = ImVec2(10.f, 2.f); style->CellPadding = ImVec2(4.f, 5.f); style->ItemSpacing = ImVec2(10.f, 5.f); style->ItemInnerSpacing = ImVec2(5.f, 5.f);