diff --git a/src/app/editor/modules/palette_editor.cc b/src/app/editor/modules/palette_editor.cc index 3d240e6b..0a2416d3 100644 --- a/src/app/editor/modules/palette_editor.cc +++ b/src/app/editor/modules/palette_editor.cc @@ -12,6 +12,68 @@ namespace yaze { namespace app { namespace editor { +using ImGui::AcceptDragDropPayload; +using ImGui::BeginChild; +using ImGui::BeginDragDropTarget; +using ImGui::BeginGroup; +using ImGui::BeginPopup; +using ImGui::BeginPopupContextItem; +using ImGui::BeginTable; +using ImGui::Button; +using ImGui::ColorButton; +using ImGui::ColorPicker4; +using ImGui::EndChild; +using ImGui::EndDragDropTarget; +using ImGui::EndGroup; +using ImGui::EndPopup; +using ImGui::EndTable; +using ImGui::GetContentRegionAvail; +using ImGui::GetStyle; +using ImGui::OpenPopup; +using ImGui::PopID; +using ImGui::PushID; +using ImGui::SameLine; +using ImGui::Selectable; +using ImGui::Separator; +using ImGui::SetClipboardText; +using ImGui::TableHeadersRow; +using ImGui::TableNextColumn; +using ImGui::TableNextRow; +using ImGui::TableSetColumnIndex; +using ImGui::TableSetupColumn; +using ImGui::Text; +using ImGui::TreeNode; +using ImGui::TreePop; + +constexpr ImGuiTableFlags kPaletteTableFlags = + ImGuiTableFlags_Reorderable | ImGuiTableFlags_Resizable | + ImGuiTableFlags_SizingStretchSame; + +namespace { +int CustomFormatString(char* buf, size_t buf_size, const char* fmt, ...) { + va_list args; + va_start(args, fmt); +#ifdef IMGUI_USE_STB_SPRINTF + int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args); +#else + int w = vsnprintf(buf, buf_size, fmt, args); +#endif + va_end(args); + if (buf == nullptr) return w; + if (w == -1 || w >= (int)buf_size) w = (int)buf_size - 1; + buf[w] = 0; + return w; +} + +static inline float color_saturate(float f) { + return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; +} + +#define F32_TO_INT8_SAT(_VAL) \ + ((int)(color_saturate(_VAL) * 255.0f + \ + 0.5f)) // Saturated, always output 0..255 +} // namespace + absl::Status PaletteEditor::Update() { if (rom()->is_loaded()) { // Initialize the labels @@ -22,25 +84,35 @@ absl::Status PaletteEditor::Update() { } } - if (ImGui::BeginTable("paletteEditorTable", 2, - ImGuiTableFlags_Reorderable | - ImGuiTableFlags_Resizable | - ImGuiTableFlags_SizingStretchSame, - ImVec2(0, 0))) { - ImGui::TableSetupColumn("Palette Groups", - ImGuiTableColumnFlags_WidthStretch, - ImGui::GetContentRegionAvail().x); - ImGui::TableSetupColumn("Editor", ImGuiTableColumnFlags_WidthStretch, - ImGui::GetContentRegionAvail().x); - ImGui::TableHeadersRow(); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); + if (BeginTable("paletteEditorTable", 2, kPaletteTableFlags, ImVec2(0, 0))) { + TableSetupColumn("Palette Groups", ImGuiTableColumnFlags_WidthStretch, + GetContentRegionAvail().x); + TableSetupColumn("Metadata", ImGuiTableColumnFlags_WidthStretch, + GetContentRegionAvail().x); + TableHeadersRow(); + TableNextRow(); + TableNextColumn(); DisplayCategoryTable(); - ImGui::TableNextColumn(); + Separator(); if (gui::SnesColorEdit4("Color Picker", current_color_, ImGuiColorEditFlags_NoAlpha)) { + // TODO: Implement new update color function } - ImGui::EndTable(); + + TableNextColumn(); + if (BeginTable("Palette Metadata", 2)) { + TableSetupColumn("Palette Name"); + TableSetupColumn("Palette Size"); + TableHeadersRow(); + TableNextRow(); + TableNextColumn(); + Text("Palette Name"); + TableNextColumn(); + Text("Palette Size"); + EndTable(); + } + + EndTable(); } CLEAR_AND_RETURN_STATUS(status_) @@ -49,77 +121,75 @@ absl::Status PaletteEditor::Update() { } void PaletteEditor::DisplayCategoryTable() { - // Check if the table is created successfully with 3 columns - if (ImGui::BeginTable("Category Table", 3)) { // 3 columns + if (BeginTable("Category Table", 6)) { + TableSetupColumn("Weapons and Gear"); + TableSetupColumn("World and Global Sprites"); + TableSetupColumn("Sprites Aux1"); + TableSetupColumn("Sprites Aux2"); + TableSetupColumn("Sprites Aux3"); + TableSetupColumn("Maps and Items"); + TableHeadersRow(); + TableNextRow(); - // Headers (optional, remove if you don't want headers) - ImGui::TableSetupColumn("Weapons and Gear"); - ImGui::TableSetupColumn("World and Enemies"); - ImGui::TableSetupColumn("Maps and Items"); - ImGui::TableHeadersRow(); - - // Start the first row - ImGui::TableNextRow(); - - // Column 1 - Weapons and Gear - ImGui::TableSetColumnIndex(0); - - if (ImGui::TreeNode("Sword")) { - status_ = DrawPaletteGroup(0); - ImGui::TreePop(); + TableSetColumnIndex(0); + if (TreeNode("Sword")) { + status_ = DrawPaletteGroup(PaletteCategory::kSword); + TreePop(); } - if (ImGui::TreeNode("Shield")) { - status_ = DrawPaletteGroup(1); - ImGui::TreePop(); + if (TreeNode("Shield")) { + status_ = DrawPaletteGroup(PaletteCategory::kShield); + TreePop(); } - if (ImGui::TreeNode("Clothes")) { - status_ = DrawPaletteGroup(2); - ImGui::TreePop(); + if (TreeNode("Clothes")) { + status_ = DrawPaletteGroup(PaletteCategory::kClothes); + TreePop(); } - // Column 2 - World and Enemies - ImGui::TableSetColumnIndex(1); - if (ImGui::TreeNode("World Colors")) { - status_ = DrawPaletteGroup(3); - ImGui::TreePop(); + TableSetColumnIndex(1); + if (TreeNode("World Colors")) { + status_ = DrawPaletteGroup(PaletteCategory::kWorldColors); + TreePop(); } - if (ImGui::TreeNode("Area Colors")) { - status_ = DrawPaletteGroup(4); - ImGui::TreePop(); + if (TreeNode("Area Colors")) { + status_ = DrawPaletteGroup(PaletteCategory::kAreaColors); + TreePop(); } - if (ImGui::TreeNode("Enemies")) { - status_ = DrawPaletteGroup(5); - ImGui::TreePop(); + if (TreeNode("Enemies")) { + status_ = DrawPaletteGroup(PaletteCategory::kGlobalSprites); + TreePop(); } - // Column 3 - Maps and Items - ImGui::TableSetColumnIndex(2); - if (ImGui::TreeNode("Dungeons")) { - status_ = DrawPaletteGroup(6); - ImGui::TreePop(); - } - if (ImGui::TreeNode("World Map")) { - status_ = DrawPaletteGroup(7); - ImGui::TreePop(); - } - if (ImGui::TreeNode("Dungeon Map")) { - status_ = DrawPaletteGroup(8); - ImGui::TreePop(); - } + TableSetColumnIndex(2); + status_ = DrawPaletteGroup(PaletteCategory::kSpritesAux1); - // Additional items in the last column, if any - { - if (ImGui::TreeNode("Triforce")) { - status_ = DrawPaletteGroup(9); - ImGui::TreePop(); - } - if (ImGui::TreeNode("Crystal")) { - status_ = DrawPaletteGroup(10); - ImGui::TreePop(); - } + TableSetColumnIndex(3); + status_ = DrawPaletteGroup(PaletteCategory::kSpritesAux2); + + TableSetColumnIndex(4); + status_ = DrawPaletteGroup(PaletteCategory::kSpritesAux3); + + TableSetColumnIndex(5); + if (TreeNode("Dungeons")) { + status_ = DrawPaletteGroup(PaletteCategory::kDungeons); + TreePop(); } - // End the table - ImGui::EndTable(); + if (TreeNode("World Map")) { + status_ = DrawPaletteGroup(PaletteCategory::kWorldMap); + TreePop(); + } + if (TreeNode("Dungeon Map")) { + status_ = DrawPaletteGroup(PaletteCategory::kDungeonMap); + TreePop(); + } + if (TreeNode("Triforce")) { + status_ = DrawPaletteGroup(PaletteCategory::kTriforce); + TreePop(); + } + if (TreeNode("Crystal")) { + status_ = DrawPaletteGroup(PaletteCategory::kCrystal); + TreePop(); + } + EndTable(); } } @@ -132,7 +202,7 @@ absl::Status PaletteEditor::EditColorInPalette(gfx::SnesPalette& palette, // Get the current color ASSIGN_OR_RETURN(auto color, palette.GetColor(index)); auto currentColor = color.rgb(); - if (ImGui::ColorPicker4("Color Picker", (float*)&palette[index])) { + if (ColorPicker4("Color Picker", (float*)&palette[index])) { // The color was modified, update it in the palette palette(index, currentColor); } @@ -162,16 +232,15 @@ absl::Status PaletteEditor::DrawPaletteGroup(int category) { static bool edit_color = false; for (int j = 0; j < size; j++) { - ImGui::Text("%d", j); - // rom()->resource_label()->SelectableLabelWithNameEdit( - // false, "Palette Group Name", std::to_string(j), - // std::string(kPaletteGroupNames[category])); + rom()->resource_label()->SelectableLabelWithNameEdit( + false, "Palette Name", /*key=*/std::to_string(j), "Unnamed Palette"); + gfx::SnesPalette* palette = palette_group.mutable_palette(j); auto pal_size = palette->size(); for (int n = 0; n < pal_size; n++) { - ImGui::PushID(n); - if ((n % 7) != 0) ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); + PushID(n); + if ((n % 7) != 0) SameLine(0.0f, GetStyle().ItemSpacing.y); auto popup_id = absl::StrCat(kPaletteCategoryNames[category].data(), j, "_", n); @@ -183,7 +252,7 @@ absl::Status PaletteEditor::DrawPaletteGroup(int category) { // EditColorInPalette(*palette, n); } - if (ImGui::BeginPopupContextItem(popup_id.c_str())) { + if (BeginPopupContextItem(popup_id.c_str())) { RETURN_IF_ERROR(HandleColorPopup(*palette, category, j, n)) } @@ -192,37 +261,12 @@ absl::Status PaletteEditor::DrawPaletteGroup(int category) { // EditColorInPalette(*palette, n); // } - ImGui::PopID(); + PopID(); } } return absl::OkStatus(); } -namespace { -int CustomFormatString(char* buf, size_t buf_size, const char* fmt, ...) { - va_list args; - va_start(args, fmt); -#ifdef IMGUI_USE_STB_SPRINTF - int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args); -#else - int w = vsnprintf(buf, buf_size, fmt, args); -#endif - va_end(args); - if (buf == nullptr) return w; - if (w == -1 || w >= (int)buf_size) w = (int)buf_size - 1; - buf[w] = 0; - return w; -} - -static inline float color_saturate(float f) { - return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; -} - -#define F32_TO_INT8_SAT(_VAL) \ - ((int)(color_saturate(_VAL) * 255.0f + \ - 0.5f)) // Saturated, always output 0..255 -} // namespace - absl::Status PaletteEditor::HandleColorPopup(gfx::SnesPalette& palette, int i, int j, int n) { auto col = gfx::ToFloatArray(palette[n]); @@ -230,8 +274,8 @@ absl::Status PaletteEditor::HandleColorPopup(gfx::SnesPalette& palette, int i, // TODO: Implement new update color function } - if (ImGui::Button("Copy as..", ImVec2(-1, 0))) ImGui::OpenPopup("Copy"); - if (ImGui::BeginPopup("Copy")) { + if (Button("Copy as..", ImVec2(-1, 0))) OpenPopup("Copy"); + if (BeginPopup("Copy")) { int cr = F32_TO_INT8_SAT(col[0]); int cg = F32_TO_INT8_SAT(col[1]); int cb = F32_TO_INT8_SAT(col[2]); @@ -240,15 +284,15 @@ absl::Status PaletteEditor::HandleColorPopup(gfx::SnesPalette& palette, int i, CustomFormatString(buf, IM_ARRAYSIZE(buf), "(%.3ff, %.3ff, %.3ff)", col[0], col[1], col[2]); - if (ImGui::Selectable(buf)) ImGui::SetClipboardText(buf); + if (Selectable(buf)) SetClipboardText(buf); CustomFormatString(buf, IM_ARRAYSIZE(buf), "(%d,%d,%d)", cr, cg, cb); - if (ImGui::Selectable(buf)) ImGui::SetClipboardText(buf); + if (Selectable(buf)) SetClipboardText(buf); CustomFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", cr, cg, cb); - if (ImGui::Selectable(buf)) ImGui::SetClipboardText(buf); - ImGui::EndPopup(); + if (Selectable(buf)) SetClipboardText(buf); + EndPopup(); } - ImGui::EndPopup(); + EndPopup(); return absl::OkStatus(); } @@ -266,67 +310,67 @@ void PaletteEditor::DisplayPalette(gfx::SnesPalette& palette, bool loaded) { } static ImVec4 backup_color; - bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags); - ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x); - open_popup |= ImGui::Button("Palette"); + bool open_popup = ColorButton("MyColor##3b", color, misc_flags); + SameLine(0, GetStyle().ItemInnerSpacing.x); + open_popup |= Button("Palette"); if (open_popup) { - ImGui::OpenPopup("mypicker"); + OpenPopup("mypicker"); backup_color = color; } - if (ImGui::BeginPopup("mypicker")) { + if (BeginPopup("mypicker")) { TEXT_WITH_SEPARATOR("Current Overworld Palette"); - ImGui::ColorPicker4("##picker", (float*)&color, - misc_flags | ImGuiColorEditFlags_NoSidePreview | - ImGuiColorEditFlags_NoSmallPreview); - ImGui::SameLine(); + ColorPicker4("##picker", (float*)&color, + misc_flags | ImGuiColorEditFlags_NoSidePreview | + ImGuiColorEditFlags_NoSmallPreview); + SameLine(); - ImGui::BeginGroup(); // Lock X position - ImGui::Text("Current ==>"); - ImGui::SameLine(); - ImGui::Text("Previous"); + BeginGroup(); // Lock X position + Text("Current ==>"); + SameLine(); + Text("Previous"); - if (ImGui::Button("Update Map Palette")) { + if (Button("Update Map Palette")) { } - ImGui::ColorButton( + ColorButton( "##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)); - ImGui::SameLine(); + SameLine(); - if (ImGui::ColorButton( + if (ColorButton( "##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40))) color = backup_color; // List of Colors in Overworld Palette - ImGui::Separator(); - ImGui::Text("Palette"); + Separator(); + Text("Palette"); for (int n = 0; n < IM_ARRAYSIZE(saved_palette_); n++) { - ImGui::PushID(n); - if ((n % 8) != 0) ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); + PushID(n); + if ((n % 8) != 0) SameLine(0.0f, GetStyle().ItemSpacing.y); - if (ImGui::ColorButton("##palette", saved_palette_[n], - palette_button_flags_2, ImVec2(20, 20))) + if (ColorButton("##palette", saved_palette_[n], palette_button_flags_2, + ImVec2(20, 20))) color = ImVec4(saved_palette_[n].x, saved_palette_[n].y, saved_palette_[n].z, color.w); // Preserve alpha! - if (ImGui::BeginDragDropTarget()) { + if (BeginDragDropTarget()) { if (const ImGuiPayload* payload = - ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) + AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) memcpy((float*)&saved_palette_[n], payload->Data, sizeof(float) * 3); if (const ImGuiPayload* payload = - ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) + AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) memcpy((float*)&saved_palette_[n], payload->Data, sizeof(float) * 4); - ImGui::EndDragDropTarget(); + EndDragDropTarget(); } - ImGui::PopID(); + PopID(); } - ImGui::EndGroup(); - ImGui::EndPopup(); + EndGroup(); + EndPopup(); } } @@ -338,34 +382,34 @@ void PaletteEditor::DrawPortablePalette(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"); + BeginChild(child_id, GetContentRegionAvail(), true, + ImGuiWindowFlags_AlwaysVerticalScrollbar)) { + BeginGroup(); // Lock X position + Text("Palette"); for (int n = 0; n < IM_ARRAYSIZE(saved_palette_); n++) { - ImGui::PushID(n); - if ((n % 8) != 0) ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); + PushID(n); + if ((n % 8) != 0) SameLine(0.0f, GetStyle().ItemSpacing.y); - if (ImGui::ColorButton("##palette", saved_palette_[n], - palette_button_flags_2, ImVec2(20, 20))) + if (ColorButton("##palette", saved_palette_[n], palette_button_flags_2, + ImVec2(20, 20))) ImVec4(saved_palette_[n].x, saved_palette_[n].y, saved_palette_[n].z, 1.0f); // Preserve alpha! - if (ImGui::BeginDragDropTarget()) { + if (BeginDragDropTarget()) { if (const ImGuiPayload* payload = - ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) + AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) memcpy((float*)&saved_palette_[n], payload->Data, sizeof(float) * 3); if (const ImGuiPayload* payload = - ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) + AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) memcpy((float*)&saved_palette_[n], payload->Data, sizeof(float) * 4); - ImGui::EndDragDropTarget(); + EndDragDropTarget(); } - ImGui::PopID(); + PopID(); } - ImGui::EndGroup(); + EndGroup(); } - ImGui::EndChild(); + EndChild(); } } // namespace editor diff --git a/src/app/editor/modules/palette_editor.h b/src/app/editor/modules/palette_editor.h index 78e21f26..b59f7107 100644 --- a/src/app/editor/modules/palette_editor.h +++ b/src/app/editor/modules/palette_editor.h @@ -14,17 +14,36 @@ namespace yaze { namespace app { namespace editor { -constexpr int kNumPalettes = 11; +constexpr int kNumPalettes = 14; + +enum PaletteCategory { + kSword, + kShield, + kClothes, + kWorldColors, + kAreaColors, + kGlobalSprites, + kSpritesAux1, + kSpritesAux2, + kSpritesAux3, + kDungeons, + kWorldMap, + kDungeonMap, + kTriforce, + kCrystal +}; static constexpr absl::string_view kPaletteCategoryNames[] = { - "Sword", "Shield", "Clothes", "World Colors", - "Area Colors", "Enemies", "Dungeons", "World Map", - "Dungeon Map", "Triforce", "Crystal"}; + "Sword", "Shield", "Clothes", "World Colors", + "Area Colors", "Global Sprites", "Sprites Aux1", "Sprites Aux2", + "Sprites Aux3", "Dungeons", "World Map", "Dungeon Map", + "Triforce", "Crystal"}; static constexpr absl::string_view kPaletteGroupNames[] = { - "swords", "shields", "armors", "ow_main", - "ow_aux", "global_sprites", "dungeon_main", "ow_mini_map", - "ow_mini_map", "3d_object", "3d_object"}; + "swords", "shields", "armors", "ow_main", + "ow_aux", "global_sprites", "sprites_aux1", "sprites_aux2", + "sprites_aux3", "dungeon_main", "ow_mini_map", "ow_mini_map", + "3d_object", "3d_object"}; namespace palette_internal { struct PaletteChange { @@ -95,7 +114,6 @@ class PaletteEditor : public SharedRom, public Editor { absl::Status Redo() override { return absl::OkStatus(); } void DisplayCategoryTable(); - absl::Status DrawPaletteGroups(); absl::Status EditColorInPalette(gfx::SnesPalette& palette, int index); absl::Status ResetColorToOriginal(gfx::SnesPalette& palette, int index, @@ -106,7 +124,6 @@ class PaletteEditor : public SharedRom, public Editor { private: absl::Status HandleColorPopup(gfx::SnesPalette& palette, int i, int j, int n); - absl::Status InitializeSavedPalette(const gfx::SnesPalette& palette) { for (int n = 0; n < palette.size(); n++) { ASSIGN_OR_RETURN(auto color, palette.GetColor(n));