5#include "absl/status/status.h"
6#include "absl/status/statusor.h"
22#include "imgui/imgui.h"
23#include "imgui/misc/cpp/imgui_stdlib.h"
24#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) {
132 .Create(width, height, 8, png_data);
155 auto palette = bitmap.palette();
156 for (
int i = 0; i < palette.size(); i++) {
159 ImVec4(palette[i].rgb().x / 255.0f, palette[i].rgb().y / 255.0f,
160 palette[i].rgb().z / 255.0f, 255.0f);
161 if (ImGui::ColorButton(absl::StrFormat(
"Palette Color %d", i).c_str(),
176 "##GfxEditChild", ImVec2(0, 0),
true,
177 ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysVerticalScrollbar);
178 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
180 static ImGuiSelectionBasicStorage selection;
181 ImGuiMultiSelectFlags flags =
182 ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
183 ImGuiMultiSelectIO* ms_io =
184 ImGui::BeginMultiSelect(flags, selection.Size,
kNumGfxSheets);
185 selection.ApplyRequests(ms_io);
186 ImGuiListClipper clipper;
188 if (ms_io->RangeSrcItem != -1)
189 clipper.IncludeItemByIndex(
190 (
int)ms_io->RangeSrcItem);
194 ImGui::BeginChild(absl::StrFormat(
"##GfxSheet%02X", key).c_str(),
195 ImVec2(0x100 + 1, 0x40 + 1),
true,
196 ImGuiWindowFlags_NoDecoration);
197 ImGui::PopStyleVar();
201 if (value.is_active()) {
202 auto texture = value.texture();
204 (ImTextureID)(intptr_t)texture,
212 if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
221 ImGui::CalcTextSize(absl::StrFormat(
"%02X", key).c_str());
222 ImVec2 rent_min(text_pos.x, text_pos.y);
223 ImVec2 rent_max(text_pos.x + text_size.x, text_pos.y + text_size.y);
226 IM_COL32(0, 125, 0, 128));
229 text_pos, IM_COL32(125, 255, 125, 255),
230 absl::StrFormat(
"%02X", key).c_str());
237 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
240 ImGui::PopStyleVar();
241 ms_io = ImGui::EndMultiSelect();
242 selection.ApplyRequests(ms_io);
244 return absl::OkStatus();
248 static int next_tab_id = 0;
249 constexpr ImGuiTabBarFlags kGfxEditTabBarFlags =
250 ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable |
251 ImGuiTabBarFlags_FittingPolicyResizeDown |
252 ImGuiTabBarFlags_TabListPopupButton;
254 if (ImGui::BeginTabBar(
"##GfxEditTabBar", kGfxEditTabBarFlags)) {
255 if (ImGui::TabItemButton(
ICON_MD_ADD, ImGuiTabItemFlags_Trailing |
256 ImGuiTabItemFlags_NoTooltip)) {
262 if (ImGui::BeginTabItem(absl::StrFormat(
"%d", sheet_id).c_str(), &open,
263 ImGuiTabItemFlags_None)) {
265 if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
268 if (ImGui::IsItemHovered()) {
269 if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
275 const auto child_id =
276 absl::StrFormat(
"##GfxEditPaletteChildWindow%d", sheet_id);
277 ImGui::BeginChild(child_id.c_str(), ImVec2(0, 0),
true,
278 ImGuiWindowFlags_NoDecoration |
279 ImGuiWindowFlags_AlwaysVerticalScrollbar |
280 ImGuiWindowFlags_AlwaysHorizontalScrollbar);
284 auto draw_tile_event = [&]() {
313 int id_to_release = -1;
316 ImGui::SetNextWindowPos(ImGui::GetIO().MousePos, ImGuiCond_Once);
317 ImGui::SetNextWindowSize(ImVec2(0x100 + 1 * 16, 0x40 + 1 * 16),
319 ImGui::Begin(absl::StrFormat(
"##GfxEditPaletteChildWindow%d",
id).c_str(),
320 &active, ImGuiWindowFlags_AlwaysUseWindowPadding);
331 if (active ==
false) {
335 if (id_to_release != -1) {
340 return absl::OkStatus();
344 if (
rom()->is_loaded()) {
345 auto palette_group = *
rom()->palette_group().get_group(
349 ImGui::SetNextItemWidth(100.f);
353 ImGui::SetNextItemWidth(100.f);
369 return absl::OkStatus();
377 for (
const auto& name : {
"Canvas",
"Animation Steps",
"Properties"})
378 ImGui::TableSetupColumn(name);
380 ImGui::TableHeadersRow();
391 link_canvas_.DrawBitmap(link_sheet, x_offset, y_offset, 4);
398 ImGui::Text(
"Placeholder");
401 if (ImGui::Button(
"Load Link Graphics (Experimental)")) {
402 if (
rom()->is_loaded()) {
417 return absl::OkStatus();
431 constexpr ImGuiTableFlags kGfxEditFlags = ImGuiTableFlags_Reorderable |
432 ImGuiTableFlags_Resizable |
433 ImGuiTableFlags_SizingStretchSame;
438 ImGui::TableSetupColumn(
"Tilemaps and Objects (SCR, PNL, OBJ)",
439 ImGuiTableColumnFlags_WidthFixed);
482 return absl::OkStatus();
486 static constexpr absl::string_view kGfxToolsetColumnNames[] = {
491 if (ImGui::BeginTable(
"GraphicsToolset", 2, ImGuiTableFlags_SizingFixedFit,
493 for (
const auto& name : kGfxToolsetColumnNames)
494 ImGui::TableSetupColumn(name.data());
509 return absl::OkStatus();
519 if (ImGui::Button(
"Open CGX")) {
527 if (ImGui::Button(
"Copy CGX Path")) {
531 if (ImGui::Button(
"Load CGX Data")) {
542 return absl::OkStatus();
548 if (ImGui::Button(
"Open SCR")) {
558 if (ImGui::Button(
"Load Scr Data")) {
573 return absl::OkStatus();
581 if (ImGui::Button(
"Open COL")) {
591 auto col_file_palette_group_status =
593 if (col_file_palette_group_status.ok()) {
605 if (ImGui::Button(
"Copy Col Path")) {
609 if (
rom()->is_loaded()) {
621 return absl::OkStatus();
630 if (ImGui::Button(
"Open OBJ")) {
639 return absl::OkStatus();
648 if (ImGui::Button(
"Open Tilemap")) {
662 return absl::OkStatus();
671 if (ImGui::Button(
"Open BIN")) {
679 if (Button(
"Copy File Path")) {
686 if (Button(
"Decompress BIN")) {
688 return absl::InvalidArgumentError(
689 "Please select a file before decompressing.");
694 return absl::OkStatus();
699 if (Button(
"Paste From Clipboard")) {
700 const char* text = ImGui::GetClipboardText();
702 const auto clipboard_data =
703 std::vector<uint8_t>(text, text + strlen(text));
704 ImGui::MemFree((
void*)text);
714 if (Button(
"Decompress Clipboard Data")) {
718 status_ = absl::InvalidArgumentError(
719 "Please paste data into the clipboard before "
724 return absl::OkStatus();
729 if (Button(
"Decompress Super Donkey Full")) {
731 return absl::InvalidArgumentError(
732 "Please select `super_donkey_1.bin` before "
737 ImGui::SetItemTooltip(
738 "Requires `super_donkey_1.bin` to be imported under the "
739 "BIN import section.");
740 return absl::OkStatus();
744 std::string title =
"Memory Editor";
746 static MemoryEditor mem_edit;
747 mem_edit.DrawWindow(title.c_str(),
temp_rom_.mutable_data(),
750 return absl::OkStatus();
761 if (
rom()->is_loaded()) {
762 auto palette_group =
rom()->palette_group().overworld_animated;
774 return absl::OkStatus();
781 std::stoi(offset,
nullptr, 16);
783 auto decompressed_data,
794 auto palette_group =
rom()->palette_group().get_group(
806 std::stoi(offset,
nullptr, 16);
808 auto decompressed_data,
818 auto palette_group =
rom()->palette_group().get_group(
830 return absl::OkStatus();
auto mutable_gfx_sheets()
static GraphicsSheetManager & GetInstance()
std::array< gfx::Bitmap, kNumGfxSheets > & gfx_sheets()
static std::string ShowOpenFileDialog()
ShowOpenFileDialog opens a file dialog and returns the selected filepath.
void UpdateBitmap(gfx::Bitmap *bitmap)
Used to update a bitmap on the screen.
void RenderBitmap(gfx::Bitmap *bitmap)
Used to render a bitmap to the screen.
absl::Status UpdateGfxEdit()
std::vector< uint8_t > scr_data_
uint64_t edit_palette_group_name_index_
std::array< gfx::Bitmap, kNumLinkSheets > link_sheets_
uint64_t clipboard_offset_
absl::Status UpdatePaletteColumn()
gfx::PaletteGroup col_file_palette_group_
std::string col_file_path_
absl::Status UpdateLinkGfxView()
std::string cgx_file_path_
absl::Status DrawMemoryEditor()
absl::Status UpdateGfxSheetList()
std::vector< uint8_t > decoded_cgx_
std::string scr_file_path_
GfxEditMode gfx_edit_mode_
std::set< uint16_t > child_window_sheets_
absl::Status DecompressSuperDonkey()
std::array< gfx::Bitmap, kNumGfxSheets > gfx_sheets_
gfx::SnesPalette col_file_palette_
std::string col_file_name_
absl::Status DrawToolset()
absl::Status DrawCgxImport()
std::vector< uint8_t > cgx_data_
void DrawGfxEditToolset()
std::string obj_file_path_
uint64_t edit_palette_index_
absl::Status DrawFileImport()
std::vector< uint8_t > import_data_
uint64_t current_palette_index_
std::vector< SDL_Color > decoded_col_
absl::Status DrawTilemapImport()
gfx::SnesPalette z3_rom_palette_
std::set< uint16_t > open_sheets_
absl::Status Update() override
absl::Status DrawScrImport()
uint64_t edit_palette_sub_index_
std::string tilemap_file_path_
gui::Canvas current_sheet_canvas_
absl::Status UpdateScadView()
std::vector< uint8_t > extra_cgx_data_
gui::Canvas import_canvas_
std::vector< uint8_t > decoded_scr_data_
std::stack< uint16_t > release_queue_
std::string cgx_file_name_
absl::Status DrawObjImport()
absl::Status DrawClipboardImport()
gui::GfxSheetAssetBrowser asset_browser_
absl::Status UpdateGfxTabView()
uint64_t num_sheets_to_load_
absl::Status DecompressImportData(int size)
absl::Status DrawExperimentalFeatures()
gui::Canvas graphics_bin_canvas_
absl::Status DrawPaletteControls()
std::string scr_file_name_
static Renderer & GetInstance()
Represents a bitmap image.
Represents a palette of colors for the Super Nintendo Entertainment System (SNES).
#define ICON_MD_FORMAT_COLOR_FILL
#define ICON_MD_CONTENT_PASTE
#define ICON_MD_SELECT_ALL
#define ICON_MD_CONTENT_COPY
#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)
void GetImageFromClipboard(std::vector< uint8_t > &data, int &width, int &height)
void CopyImageToClipboard(const std::vector< uint8_t > &data)
Editors are the view controllers for the application.
const std::string kSuperDonkeySprites[]
constexpr ImGuiTableFlags kGfxEditTableFlags
const std::string kSuperDonkeyTiles[]
constexpr int kNintendoMode1
absl::StatusOr< std::vector< uint8_t > > DecompressV2(const uint8_t *data, int offset, int size, int mode)
Decompresses a buffer of data using the LC_LZ2 algorithm.
constexpr int kTilesheetHeight
constexpr int kTilesheetWidth
constexpr const char * kPaletteGroupAddressesKeys[]
constexpr int kTilesheetDepth
absl::StatusOr< PaletteGroup > CreatePaletteGroupFromColFile(std::vector< SnesColor > &palette_rows)
std::vector< SnesColor > GetColFileData(uint8_t *data)
std::vector< uint8_t > SnesTo8bppSheet(const std::vector< uint8_t > &sheet, int bpp, int num_sheets)
void BitmapCanvasPipeline(gui::Canvas &canvas, const gfx::Bitmap &bitmap, int width, int height, int tile_size, bool is_loaded, bool scrollbar, int canvas_id)
bool InputHex(const char *label, uint64_t *data)
void SelectablePalettePipeline(uint64_t &palette_id, bool &refresh_graphics, gfx::SnesPalette &palette)
bool InputHexByte(const char *label, uint8_t *data, float input_width, bool no_step)
void TextWithSeparators(const absl::string_view &text)
Main namespace for the application.
absl::StatusOr< std::array< gfx::Bitmap, kNumLinkSheets > > LoadLinkGraphics(const Rom &rom)
Loads the players 4bpp graphics sheet from Rom data.
constexpr uint32_t kNumGfxSheets