3#include "ImGuiFileDialog/ImGuiFileDialog.h"
4#include "absl/status/status.h"
5#include "absl/status/statusor.h"
20#include "imgui/imgui.h"
21#include "imgui/misc/cpp/imgui_stdlib.h"
22#include "imgui_memory_editor.h"
33using ImGui::InputText;
35using ImGui::TableNextColumn;
37static constexpr absl::string_view kGfxToolsetColumnNames[] = {
43 ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable |
44 ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable |
45 ImGuiTableFlags_SizingFixedFit;
48 ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable |
49 ImGuiTabBarFlags_FittingPolicyResizeDown |
50 ImGuiTabBarFlags_TabListPopupButton;
53 ImGuiTableFlags_Resizable |
54 ImGuiTableFlags_SizingStretchSame;
70 return absl::OkStatus();
78 for (
const auto& name :
79 {
"Tilesheets",
"Current Graphics",
"Palette Controls"})
80 ImGui::TableSetupColumn(name);
82 ImGui::TableHeadersRow();
88 if (
rom()->is_loaded()) {
94 if (
rom()->is_loaded()) {
101 return absl::OkStatus();
105 if (ImGui::BeginTable(
"##GfxEditToolset", 9, ImGuiTableFlags_SizingFixedFit,
107 for (
const auto& name :
108 {
"Select",
"Pencil",
"Fill",
"Copy Sheet",
"Paste Sheet",
"Zoom Out",
109 "Zoom In",
"Current Color",
"Tile Size"})
110 ImGui::TableSetupColumn(name);
131 std::vector<uint8_t> png_data =
139 std::vector<uint8_t> png_data;
142 if (png_data.size() > 0) {
144 ->mutable_gfx_sheets()
146 .Create(width, height, 8, png_data);
169 auto palette = bitmap.palette();
170 for (
int i = 0; i < 8; i++) {
173 ImVec4(palette[i].rgb().x / 255.0f, palette[i].rgb().y / 255.0f,
174 palette[i].rgb().z / 255.0f, 255.0f);
175 if (ImGui::ColorButton(absl::StrFormat(
"Palette Color %d", i).c_str(),
190 "##GfxEditChild", ImVec2(0, 0),
true,
191 ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysVerticalScrollbar);
192 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
194 static ImGuiSelectionBasicStorage selection;
195 ImGuiMultiSelectFlags flags =
196 ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
197 ImGuiMultiSelectIO* ms_io =
198 ImGui::BeginMultiSelect(flags, selection.Size,
kNumGfxSheets);
199 selection.ApplyRequests(ms_io);
200 ImGuiListClipper clipper;
202 if (ms_io->RangeSrcItem != -1)
203 clipper.IncludeItemByIndex(
204 (
int)ms_io->RangeSrcItem);
207 for (
auto& value :
rom()->gfx_sheets()) {
208 ImGui::BeginChild(absl::StrFormat(
"##GfxSheet%02X", key).c_str(),
209 ImVec2(0x100 + 1, 0x40 + 1),
true,
210 ImGuiWindowFlags_NoDecoration);
211 ImGui::PopStyleVar();
215 if (value.is_active()) {
216 auto texture = value.texture();
226 if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
235 ImGui::CalcTextSize(absl::StrFormat(
"%02X", key).c_str());
236 ImVec2 rent_min(text_pos.x, text_pos.y);
237 ImVec2 rent_max(text_pos.x + text_size.x, text_pos.y + text_size.y);
240 IM_COL32(0, 125, 0, 128));
243 text_pos, IM_COL32(125, 255, 125, 255),
244 absl::StrFormat(
"%02X", key).c_str());
251 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
254 ImGui::PopStyleVar();
255 ms_io = ImGui::EndMultiSelect();
256 selection.ApplyRequests(ms_io);
258 return absl::OkStatus();
262 static int next_tab_id = 0;
265 if (ImGui::TabItemButton(
ICON_MD_ADD, ImGuiTabItemFlags_Trailing |
266 ImGuiTabItemFlags_NoTooltip)) {
272 if (ImGui::BeginTabItem(absl::StrFormat(
"%d", sheet_id).c_str(), &open,
273 ImGuiTabItemFlags_None)) {
275 if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
278 if (ImGui::IsItemHovered()) {
279 if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
285 const auto child_id =
286 absl::StrFormat(
"##GfxEditPaletteChildWindow%d", sheet_id);
287 ImGui::BeginChild(child_id.c_str(), ImVec2(0, 0),
true,
288 ImGuiWindowFlags_NoDecoration |
289 ImGuiWindowFlags_AlwaysVerticalScrollbar |
290 ImGuiWindowFlags_AlwaysHorizontalScrollbar);
294 auto draw_tile_event = [&]() {
323 int id_to_release = -1;
326 ImGui::SetNextWindowPos(ImGui::GetIO().MousePos, ImGuiCond_Once);
327 ImGui::SetNextWindowSize(ImVec2(0x100 + 1 * 16, 0x40 + 1 * 16),
329 ImGui::Begin(absl::StrFormat(
"##GfxEditPaletteChildWindow%d",
id).c_str(),
330 &active, ImGuiWindowFlags_AlwaysUseWindowPadding);
341 if (active ==
false) {
345 if (id_to_release != -1) {
350 return absl::OkStatus();
354 if (
rom()->is_loaded()) {
355 auto palette_group = *
rom()->palette_group().get_group(
359 ImGui::SetNextItemWidth(100.f);
361 kPaletteGroupAddressesKeys,
362 IM_ARRAYSIZE(kPaletteGroupAddressesKeys));
363 ImGui::SetNextItemWidth(100.f);
372 ->mutable_gfx_sheets()
380 return absl::OkStatus();
388 for (
const auto& name : {
"Canvas",
"Animation Steps",
"Properties"})
389 ImGui::TableSetupColumn(name);
391 ImGui::TableHeadersRow();
398 for (
auto link_sheet : *
rom()->mutable_link_graphics()) {
409 ImGui::Text(
"Placeholder");
412 if (ImGui::Button(
"Load Link Graphics (Experimental)")) {
413 if (
rom()->is_loaded()) {
428 return absl::OkStatus();
445 ImGui::TableSetupColumn(
"Tilemaps and Objects (SCR, PNL, OBJ)",
446 ImGuiTableColumnFlags_WidthFixed);
489 return absl::OkStatus();
493 if (ImGui::BeginTable(
"GraphicsToolset", 2, ImGuiTableFlags_SizingFixedFit,
495 for (
const auto& name : kGfxToolsetColumnNames)
496 ImGui::TableSetupColumn(name.data());
511 return absl::OkStatus();
523 ImGuiFileDialog::Instance()->GetFilePathName().c_str(),
526 ImGuiFileDialog::Instance()->GetCurrentFileName().c_str(),
532 if (ImGui::Button(
"Copy CGX Path")) {
536 if (ImGui::Button(
"Load CGX Data")) {
547 return absl::OkStatus();
554 "ImportScrKey",
".SCR,.scr,.BAK\0",
"Open SCR", [
this]() {
556 ImGuiFileDialog::Instance()->GetFilePathName().c_str(),
559 ImGuiFileDialog::Instance()->GetCurrentFileName().c_str(),
567 if (ImGui::Button(
"Load Scr Data")) {
582 return absl::OkStatus();
591 "ImportColKey",
".COL,.col,.BAK,.bak\0",
"Open COL", [
this]() {
593 ImGuiFileDialog::Instance()->GetFilePathName().c_str(),
596 ImGuiFileDialog::Instance()->GetCurrentFileName().c_str(),
604 auto col_file_palette_group_status =
606 if (col_file_palette_group_status.ok()) {
617 if (ImGui::Button(
"Copy Col Path")) {
621 if (
rom()->is_loaded()) {
625 IM_ARRAYSIZE(kPaletteGroupAddressesKeys));
633 return absl::OkStatus();
643 "ImportObjKey",
".obj,.OBJ,.bak,.BAK\0",
"Open OBJ", [
this]() {
645 ImGuiFileDialog::Instance()->GetFilePathName().c_str(),
651 return absl::OkStatus();
661 "ImportTilemapKey",
".DAT,.dat,.BIN,.bin,.hex,.HEX\0",
"Open Tilemap",
664 ImGuiFileDialog::Instance()->GetFilePathName().c_str(),
675 return absl::OkStatus();
685 strncpy(
file_path_, ImGuiFileDialog::Instance()->GetFilePathName().c_str(),
691 if (Button(
"Copy File Path")) {
698 if (Button(
"Decompress BIN")) {
702 return absl::InvalidArgumentError(
703 "Please select a file before importing.");
707 return absl::OkStatus();
712 if (Button(
"Paste From Clipboard")) {
713 const char* text = ImGui::GetClipboardText();
715 const auto clipboard_data = std::vector<uint8_t>(text, text + strlen(text));
716 ImGui::MemFree((
void*)text);
726 if (Button(
"Decompress Clipboard Data")) {
730 status_ = absl::InvalidArgumentError(
731 "Please paste data into the clipboard before "
736 return absl::OkStatus();
741 if (Button(
"Decompress Super Donkey Full")) {
745 return absl::InvalidArgumentError(
746 "Please select `super_donkey_1.bin` before "
750 ImGui::SetItemTooltip(
751 "Requires `super_donkey_1.bin` to be imported under the "
752 "BIN import section.");
753 return absl::OkStatus();
757 std::string title =
"Memory Editor";
759 static MemoryEditor mem_edit;
762 return absl::OkStatus();
773 if (
rom()->is_loaded()) {
774 auto palette_group =
rom()->palette_group().overworld_animated;
786 return absl::OkStatus();
793 std::stoi(offset,
nullptr, 16);
795 auto decompressed_data,
806 auto palette_group =
rom()->palette_group().get_group(
818 std::stoi(offset,
nullptr, 16);
820 auto decompressed_data,
830 auto palette_group =
rom()->palette_group().get_group(
842 return absl::OkStatus();
absl::Status LoadFromFile(const std::string &filename, bool z3_load=true)
absl::Status LoadFromBytes(const std::vector< uint8_t > &data)
static Renderer & GetInstance()
void RenderBitmap(gfx::Bitmap *bitmap)
Used to render a bitmap to the screen.
void UpdateBitmap(gfx::Bitmap *bitmap, bool use_sdl_update=false)
Used to update a bitmap on the screen.
absl::Status DecompressSuperDonkey()
absl::Status DrawClipboardImport()
uint64_t edit_palette_sub_index_
absl::Status DrawTilemapImport()
uint64_t num_sheets_to_load_
absl::Status DrawToolset()
std::vector< uint8_t > cgx_data_
absl::Status DecompressImportData(int size)
std::set< uint16_t > child_window_sheets_
std::array< gfx::Bitmap, kNumGfxSheets > gfx_sheets_
absl::Status UpdateGfxSheetList()
uint64_t edit_palette_index_
absl::Status Update() override
absl::Status DrawFileImport()
gui::Canvas import_canvas_
gfx::PaletteGroup col_file_palette_group_
absl::Status UpdateLinkGfxView()
absl::Status DrawObjImport()
gui::GfxSheetAssetBrowser asset_browser_
absl::Status DrawPaletteControls()
std::vector< SDL_Color > decoded_col_
absl::Status UpdateGfxEdit()
std::vector< uint8_t > extra_cgx_data_
std::vector< uint8_t > decoded_scr_data_
std::vector< uint8_t > decoded_cgx_
std::vector< uint8_t > import_data_
absl::Status DrawCgxImport()
absl::Status UpdateGfxTabView()
gui::Canvas current_sheet_canvas_
absl::Status DrawScrImport()
std::stack< uint16_t > release_queue_
gfx::SnesPalette col_file_palette_
uint64_t current_palette_index_
uint64_t clipboard_offset_
absl::Status UpdateScadView()
gfx::SnesPalette z3_rom_palette_
char tilemap_file_path_[256]
GfxEditMode gfx_edit_mode_
absl::Status DrawExperimentalFeatures()
void DrawGfxEditToolset()
absl::Status DrawMemoryEditor()
std::vector< uint8_t > scr_data_
uint64_t edit_palette_group_name_index_
gui::Canvas graphics_bin_canvas_
std::set< uint16_t > open_sheets_
absl::Status UpdatePaletteColumn()
Represents a bitmap image.
absl::Status ApplyPalette(const SnesPalette &palette)
Copy color data from the SnesPalette into the SDL_Palette.
void Create(int width, int height, int depth, const std::vector< uint8_t > &data)
Creates a bitmap object with the provided graphical data.
Represents a palette of colors for the Super Nintendo Entertainment System (SNES).
void DrawBackground(ImVec2 canvas_size=ImVec2(0, 0), bool drag=false)
void DrawGrid(float grid_step=64.0f, int tile_id_offset=8)
void DrawTileOnBitmap(int tile_size, gfx::Bitmap *bitmap, ImVec4 color)
void DrawBitmap(const Bitmap &bitmap, int border_offset=0, bool ready=true)
void UpdateColorPainter(gfx::Bitmap &bitmap, const ImVec4 &color, const std::function< void()> &event, int tile_size, float scale=1.0f)
void DrawContextMenu(gfx::Bitmap *bitmap=nullptr)
#define BEGIN_TABLE(l, n, f)
#define RETURN_IF_ERROR(expression)
#define ASSIGN_OR_RETURN(type_variable_name, expression)
#define CLEAR_AND_RETURN_STATUS(status)
#define HOVER_HINT(string)
#define ICON_MD_FORMAT_COLOR_FILL
#define ICON_MD_CONTENT_PASTE
#define ICON_MD_SELECT_ALL
#define ICON_MD_CONTENT_COPY
void CopyImageToClipboard(const std::vector< uint8_t > &data)
void GetImageFromClipboard(std::vector< uint8_t > &data, int &width, int &height)
constexpr ImGuiTabBarFlags kGfxEditTabBarFlags
const std::string kSuperDonkeyTiles[]
constexpr ImGuiTableFlags kGfxEditTableFlags
const std::string kSuperDonkeySprites[]
constexpr ImGuiTableFlags kGfxEditFlags
absl::StatusOr< std::vector< uint8_t > > DecompressV2(const uchar *data, int offset, int size, int mode)
Decompresses a buffer of data using the LC_LZ2 algorithm.
constexpr int kNintendoMode1
constexpr int kTilesheetDepth
constexpr int kTilesheetWidth
std::vector< uint8_t > SnesTo8bppSheet(const std::vector< uint8_t > &sheet, int bpp)
std::vector< SnesColor > GetColFileData(uint8_t *data)
absl::StatusOr< PaletteGroup > CreatePaletteGroupFromColFile(std::vector< SnesColor > &palette_rows)
constexpr int kTilesheetHeight
constexpr const char * kPaletteGroupAddressesKeys[]
bool InputHexByte(const char *label, uint8_t *data, float input_width, bool no_step)
bool InputHex(const char *label, uint64_t *data)
void SelectablePalettePipeline(uint64_t &palette_id, bool &refresh_graphics, gfx::SnesPalette &palette)
void FileDialogPipeline(absl::string_view display_key, absl::string_view file_extensions, std::optional< absl::string_view > button_text, std::function< void()> callback)
void TextWithSeparators(const absl::string_view &text)
void BitmapCanvasPipeline(gui::Canvas &canvas, const gfx::Bitmap &bitmap, int width, int height, int tile_size, bool is_loaded, bool scrollbar, int canvas_id)
constexpr uint32_t kNumGfxSheets
void Draw(const std::array< gfx::Bitmap, kNumGfxSheets > &bmp_manager)
void Initialize(const std::array< gfx::Bitmap, kNumGfxSheets > &bmp_manager)