3#include "ImGuiFileDialog/ImGuiFileDialog.h"
4#include "absl/status/status.h"
5#include "absl/status/statusor.h"
21#include "imgui/imgui.h"
22#include "imgui/misc/cpp/imgui_stdlib.h"
23#include "imgui_memory_editor.h"
34using ImGui::InputText;
36using ImGui::TableNextColumn;
39 ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable |
40 ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable |
41 ImGuiTableFlags_SizingFixedFit;
44 if (ImGui::BeginTabBar(
"##TabBar")) {
57 return absl::OkStatus();
61 if (ImGui::BeginTabItem(
"Sheet Editor")) {
64 for (
const auto& name :
65 {
"Tilesheets",
"Current Graphics",
"Palette Controls"})
66 ImGui::TableSetupColumn(name);
68 ImGui::TableHeadersRow();
74 if (
rom()->is_loaded()) {
80 if (
rom()->is_loaded()) {
88 return absl::OkStatus();
92 if (ImGui::BeginTable(
"##GfxEditToolset", 9, ImGuiTableFlags_SizingFixedFit,
94 for (
const auto& name :
95 {
"Select",
"Pencil",
"Fill",
"Copy Sheet",
"Paste Sheet",
"Zoom Out",
96 "Zoom In",
"Current Color",
"Tile Size"})
97 ImGui::TableSetupColumn(name);
118 std::vector<uint8_t> png_data =
126 std::vector<uint8_t> png_data;
129 if (png_data.size() > 0) {
131 ->mutable_gfx_sheets()
133 .Create(width, height, 8, png_data);
156 auto palette = bitmap.palette();
157 for (
int i = 0; i < 8; i++) {
160 ImVec4(palette[i].rgb().x / 255.0f, palette[i].rgb().y / 255.0f,
161 palette[i].rgb().z / 255.0f, 255.0f);
162 if (ImGui::ColorButton(absl::StrFormat(
"Palette Color %d", i).c_str(),
177 "##GfxEditChild", ImVec2(0, 0),
true,
178 ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysVerticalScrollbar);
179 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
181 static ImGuiSelectionBasicStorage selection;
182 ImGuiMultiSelectFlags flags =
183 ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
184 ImGuiMultiSelectIO* ms_io =
185 ImGui::BeginMultiSelect(flags, selection.Size,
kNumGfxSheets);
186 selection.ApplyRequests(ms_io);
187 ImGuiListClipper clipper;
189 if (ms_io->RangeSrcItem != -1)
190 clipper.IncludeItemByIndex(
191 (
int)ms_io->RangeSrcItem);
194 for (
auto& value :
rom()->gfx_sheets()) {
195 ImGui::BeginChild(absl::StrFormat(
"##GfxSheet%02X", key).c_str(),
196 ImVec2(0x100 + 1, 0x40 + 1),
true,
197 ImGuiWindowFlags_NoDecoration);
198 ImGui::PopStyleVar();
202 if (value.is_active()) {
203 auto texture = value.texture();
205 (ImTextureID)(intptr_t)texture,
213 if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
222 ImGui::CalcTextSize(absl::StrFormat(
"%02X", key).c_str());
223 ImVec2 rent_min(text_pos.x, text_pos.y);
224 ImVec2 rent_max(text_pos.x + text_size.x, text_pos.y + text_size.y);
227 IM_COL32(0, 125, 0, 128));
230 text_pos, IM_COL32(125, 255, 125, 255),
231 absl::StrFormat(
"%02X", key).c_str());
238 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
241 ImGui::PopStyleVar();
242 ms_io = ImGui::EndMultiSelect();
243 selection.ApplyRequests(ms_io);
245 return absl::OkStatus();
249 static int next_tab_id = 0;
250 constexpr ImGuiTabBarFlags kGfxEditTabBarFlags =
251 ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable |
252 ImGuiTabBarFlags_FittingPolicyResizeDown |
253 ImGuiTabBarFlags_TabListPopupButton;
255 if (ImGui::BeginTabBar(
"##GfxEditTabBar", kGfxEditTabBarFlags)) {
256 if (ImGui::TabItemButton(
ICON_MD_ADD, ImGuiTabItemFlags_Trailing |
257 ImGuiTabItemFlags_NoTooltip)) {
263 if (ImGui::BeginTabItem(absl::StrFormat(
"%d", sheet_id).c_str(), &open,
264 ImGuiTabItemFlags_None)) {
266 if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
269 if (ImGui::IsItemHovered()) {
270 if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
276 const auto child_id =
277 absl::StrFormat(
"##GfxEditPaletteChildWindow%d", sheet_id);
278 ImGui::BeginChild(child_id.c_str(), ImVec2(0, 0),
true,
279 ImGuiWindowFlags_NoDecoration |
280 ImGuiWindowFlags_AlwaysVerticalScrollbar |
281 ImGuiWindowFlags_AlwaysHorizontalScrollbar);
285 auto draw_tile_event = [&]() {
314 int id_to_release = -1;
317 ImGui::SetNextWindowPos(ImGui::GetIO().MousePos, ImGuiCond_Once);
318 ImGui::SetNextWindowSize(ImVec2(0x100 + 1 * 16, 0x40 + 1 * 16),
320 ImGui::Begin(absl::StrFormat(
"##GfxEditPaletteChildWindow%d",
id).c_str(),
321 &active, ImGuiWindowFlags_AlwaysUseWindowPadding);
332 if (active ==
false) {
336 if (id_to_release != -1) {
341 return absl::OkStatus();
345 if (
rom()->is_loaded()) {
346 auto palette_group = *
rom()->palette_group().get_group(
350 ImGui::SetNextItemWidth(100.f);
352 kPaletteGroupAddressesKeys,
353 IM_ARRAYSIZE(kPaletteGroupAddressesKeys));
354 ImGui::SetNextItemWidth(100.f);
363 ->mutable_gfx_sheets()
371 return absl::OkStatus();
379 for (
const auto& name : {
"Canvas",
"Animation Steps",
"Properties"})
380 ImGui::TableSetupColumn(name);
382 ImGui::TableHeadersRow();
389 for (
auto link_sheet : *
rom()->mutable_link_graphics()) {
400 ImGui::Text(
"Placeholder");
403 if (ImGui::Button(
"Load Link Graphics (Experimental)")) {
404 if (
rom()->is_loaded()) {
419 return absl::OkStatus();
433 constexpr ImGuiTableFlags kGfxEditFlags = ImGuiTableFlags_Reorderable |
434 ImGuiTableFlags_Resizable |
435 ImGuiTableFlags_SizingStretchSame;
440 ImGui::TableSetupColumn(
"Tilemaps and Objects (SCR, PNL, OBJ)",
441 ImGuiTableColumnFlags_WidthFixed);
484 return absl::OkStatus();
488 static constexpr absl::string_view kGfxToolsetColumnNames[] = {
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 =
716 std::vector<uint8_t>(text, text + strlen(text));
717 ImGui::MemFree((
void*)text);
727 if (Button(
"Decompress Clipboard Data")) {
731 status_ = absl::InvalidArgumentError(
732 "Please paste data into the clipboard before "
737 return absl::OkStatus();
742 if (Button(
"Decompress Super Donkey Full")) {
746 return absl::InvalidArgumentError(
747 "Please select `super_donkey_1.bin` before "
751 ImGui::SetItemTooltip(
752 "Requires `super_donkey_1.bin` to be imported under the "
753 "BIN import section.");
754 return absl::OkStatus();
758 std::string title =
"Memory Editor";
760 static MemoryEditor mem_edit;
763 return absl::OkStatus();
774 if (
rom()->is_loaded()) {
775 auto palette_group =
rom()->palette_group().overworld_animated;
787 return absl::OkStatus();
794 std::stoi(offset,
nullptr, 16);
796 auto decompressed_data,
807 auto palette_group =
rom()->palette_group().get_group(
819 std::stoi(offset,
nullptr, 16);
821 auto decompressed_data,
831 auto palette_group =
rom()->palette_group().get_group(
843 return absl::OkStatus();
absl::Status LoadFromFile(const std::string &filename, bool z3_load=true)
absl::Status LoadFromBytes(const std::vector< uint8_t > &data)
void UpdateBitmap(gfx::Bitmap *bitmap)
Used to update a bitmap on the screen.
static Renderer & GetInstance()
void RenderBitmap(gfx::Bitmap *bitmap)
Used to render a bitmap to 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)
const std::string kSuperDonkeyTiles[]
constexpr ImGuiTableFlags kGfxEditTableFlags
const std::string kSuperDonkeySprites[]
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
std::vector< uint8_t > SnesTo8bppSheet(const std::vector< uint8_t > &sheet, int bpp, int num_sheets)
constexpr int kTilesheetWidth
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)