6#include "absl/strings/str_format.h"
42 ImGui::TextColored(ImVec4(1, 0, 0, 1),
"GameData not loaded");
64 ImGui::TextDisabled(
"Select a color to edit");
74 int num_palettes = dungeon_pal_group.
size();
76 ImGui::Text(
"Dungeon Palette:");
79 if (ImGui::BeginCombo(
82 for (
int i = 0; i < num_palettes; i++) {
84 if (ImGui::Selectable(absl::StrFormat(
"Palette %d", i).c_str(),
90 ImGui::SetItemDefaultFocus();
100 ImGui::SeparatorText(
110 ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_PickerHueWheel)) {
124 ImGui::Text(
"RGB (0-255): (%d, %d, %d)",
128 ImGui::Text(
"SNES BGR555: 0x%04X", original_color.snes());
130 if (ImGui::Button(
"Reset to Original")) {
132 ImVec4(original_color.rgb().x / 255.0f, original_color.rgb().y / 255.0f,
133 original_color.rgb().z / 255.0f, 1.0f);
146 const std::string& title) {
147 if (ImGui::BeginPopupModal(title.c_str(),
nullptr,
148 ImGuiWindowFlags_AlwaysAutoResize)) {
149 ImGui::Text(
"Enhanced Palette Editor");
155 if (ImGui::CollapsingHeader(
"Palette Analysis")) {
159 if (ImGui::CollapsingHeader(
"ROM Palette Manager") &&
rom_) {
172 if (ImGui::Button(
"Save Backup")) {
176 if (ImGui::Button(
"Restore Backup")) {
180 if (ImGui::Button(
"Close")) {
181 ImGui::CloseCurrentPopup();
194 ImGui::Text(
"No ROM loaded");
207 ImGui::Text(
"Preview of %s:",
219 const std::string& title) {
224 ImGui::Text(
"Bitmap Color Analysis");
228 ImGui::Text(
"Bitmap is not active");
233 std::map<uint8_t, int> pixel_counts;
234 const auto& data = bitmap.
vector();
236 for (uint8_t pixel : data) {
237 uint8_t palette_index = pixel & 0x0F;
238 pixel_counts[palette_index]++;
241 ImGui::Text(
"Bitmap Size: %d x %d (%zu pixels)", bitmap.
width(),
242 bitmap.
height(), data.size());
245 ImGui::Text(
"Pixel Distribution:");
247 int total_pixels =
static_cast<int>(data.size());
251 .x_label =
"Palette Index",
253 .flags = ImPlotFlags_NoBoxSelect,
254 .x_axis_flags = ImPlotAxisFlags_AutoFit,
255 .y_axis_flags = ImPlotAxisFlags_AutoFit};
256 std::vector<double> x;
257 std::vector<double> y;
258 x.reserve(pixel_counts.size());
259 y.reserve(pixel_counts.size());
260 for (
const auto& [index, count] : pixel_counts) {
261 x.push_back(
static_cast<double>(index));
262 y.push_back(
static_cast<double>(count));
265 if (plot && !x.empty()) {
266 ImPlot::PlotBars(
"Usage", x.data(), y.data(),
static_cast<int>(x.size()),
267 0.67, 0.0, ImPlotBarsFlags_None);
284 if (palette_index >= 0 && palette_index < 8) {
296 }
catch (
const std::exception& e) {
323 for (
int i = 0; i < static_cast<int>(palette.
size()); i++) {
327 auto color = palette[i];
328 ImVec4 display_color = color.rgb();
331 if (ImGui::ColorButton(
"##color", display_color,
332 ImGuiColorEditFlags_NoTooltip, ImVec2(30, 30))) {
339 if (ImGui::BeginPopupContextItem()) {
340 ImGui::Text(
"Color %d (0x%04X)", i, color.snes());
342 if (ImGui::MenuItem(
"Edit Color")) {
348 if (ImGui::MenuItem(
"Reset to Black")) {
354 if (ImGui::IsItemHovered()) {
355 ImGui::SetTooltip(
"Color %d\nSNES: 0x%04X\nRGB: (%d, %d, %d)", i,
356 color.snes(),
static_cast<int>(display_color.x * 255),
357 static_cast<int>(display_color.y * 255),
358 static_cast<int>(display_color.z * 255));
366 std::string popup_id =
369 ImGui::OpenPopup(popup_id.c_str());
370 if (ImGui::BeginPopupModal(popup_id.c_str(),
nullptr,
371 ImGuiWindowFlags_AlwaysAutoResize)) {
373 if (ImGui::ColorEdit4(
375 ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_DisplayRGB)) {
379 if (ImGui::Button(
"Apply")) {
381 ImGui::CloseCurrentPopup();
384 if (ImGui::Button(
"Cancel")) {
386 ImGui::CloseCurrentPopup();
399 ImGui::Text(
"No ROM palettes available");
403 ImGui::Text(
"Palette Group:");
406 [](
void* data,
int idx,
const char** out_text) ->
bool {
407 auto* names =
static_cast<std::vector<std::string>*
>(data);
408 if (idx < 0 || idx >=
static_cast<int>(names->size()))
410 *out_text = (*names)[idx].c_str();
416 ImGui::Text(
"Palette Index:");
420 ImGui::Text(
"Preview:");
422 for (
int i = 0; i < 8 && i < static_cast<int>(preview_palette.size());
426 auto color = preview_palette[i];
427 ImVec4 display_color = color.rgb();
428 ImGui::ColorButton((
"##preview" + std::to_string(i)).c_str(),
429 display_color, ImGuiColorEditFlags_NoTooltip,
437 ImVec4 rgba = color.
rgb();
439 ImGui::PushID(color_index);
441 if (ImGui::ColorEdit4(
442 "##color_edit", &rgba.x,
443 ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_DisplayRGB)) {
447 ImGui::Text(
"SNES Color: 0x%04X", color.
snes());
449 int r = (color.
snes() & 0x1F);
450 int g = (color.
snes() >> 5) & 0x1F;
451 int b = (color.
snes() >> 10) & 0x1F;
453 if (ImGui::SliderInt(
"Red", &r, 0, 31)) {
454 uint16_t new_color = (color.
snes() & 0xFFE0) | (r & 0x1F);
457 if (ImGui::SliderInt(
"Green", &g, 0, 31)) {
458 uint16_t new_color = (color.
snes() & 0xFC1F) | ((g & 0x1F) << 5);
461 if (ImGui::SliderInt(
"Blue", &b, 0, 31)) {
462 uint16_t new_color = (color.
snes() & 0x83FF) | ((b & 0x1F) << 10);
470 ImGui::Text(
"Palette Information:");
471 ImGui::Text(
"Size: %zu colors", palette.
size());
473 std::map<uint16_t, int> color_frequency;
474 for (
int i = 0; i < static_cast<int>(palette.
size()); i++) {
475 color_frequency[palette[i].snes()]++;
478 ImGui::Text(
"Unique Colors: %zu", color_frequency.size());
480 if (color_frequency.size() < palette.
size()) {
481 ImGui::TextColored(ImVec4(1, 1, 0, 1),
482 "Warning: Duplicate colors detected!");
483 if (ImGui::TreeNode(
"Duplicate Colors")) {
484 for (
const auto& [
snes_color, count] : color_frequency) {
487 ImGui::ColorButton((
"##dup" + std::to_string(
snes_color)).c_str(),
488 display_color, ImGuiColorEditFlags_NoTooltip,
491 ImGui::Text(
"0x%04X appears %d times",
snes_color, count);
503 .x_label =
"Color Index",
505 .flags = ImPlotFlags_NoBoxSelect,
506 .x_axis_flags = ImPlotAxisFlags_AutoFit,
507 .y_axis_flags = ImPlotAxisFlags_AutoFit};
508 std::vector<double> x;
509 std::vector<double> y;
510 x.reserve(color_frequency.size());
511 y.reserve(color_frequency.size());
512 for (
const auto& [
snes_color, count] : color_frequency) {
514 y.push_back(
static_cast<double>(count));
517 if (plot && !x.empty()) {
518 ImPlot::PlotBars(
"Count", x.data(), y.data(),
static_cast<int>(x.size()),
519 0.5, 0.0, ImPlotBarsFlags_None);
523 float total_brightness = 0.0f;
524 float min_brightness = 1.0f;
525 float max_brightness = 0.0f;
527 for (
int i = 0; i < static_cast<int>(palette.
size()); i++) {
528 ImVec4 color = palette[i].rgb();
529 float brightness = (color.x + color.y + color.z) / 3.0f;
530 total_brightness += brightness;
531 min_brightness = std::min(min_brightness, brightness);
532 max_brightness = std::max(max_brightness, brightness);
535 float avg_brightness = total_brightness / palette.
size();
538 ImGui::Text(
"Brightness Analysis:");
539 ImGui::Text(
"Average: %.2f", avg_brightness);
540 ImGui::Text(
"Range: %.2f - %.2f", min_brightness, max_brightness);
542 ImGui::Text(
"Brightness Distribution:");
543 ImGui::ProgressBar(avg_brightness, ImVec2(-1, 0),
"Avg");
555 if (palette_groups.overworld_main.size() > 0) {
559 if (palette_groups.overworld_aux.size() > 0) {
563 if (palette_groups.overworld_animated.size() > 0) {
567 if (palette_groups.dungeon_main.size() > 0) {
571 if (palette_groups.global_sprites.size() > 0) {
575 if (palette_groups.armors.size() > 0) {
579 if (palette_groups.swords.size() > 0) {
585 }
catch (
const std::exception& e) {
586 LOG_ERROR(
"Enhanced Palette Editor",
"Failed to load ROM palettes");
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
void QueueTextureCommand(TextureCommandType type, Bitmap *bitmap)
Represents a bitmap image optimized for SNES ROM hacking.
const SnesPalette & palette() const
const std::vector< uint8_t > & vector() const
void SetPalette(const SnesPalette &palette)
Set the palette for the bitmap using SNES palette format.
void SetPaletteWithTransparent(const SnesPalette &palette, size_t index, int length=7)
Set the palette with a transparent color.
constexpr ImVec4 rgb() const
Get RGB values (WARNING: stored as 0-255 in ImVec4)
constexpr uint16_t snes() const
Get SNES 15-bit color.
Represents a palette of colors for the Super Nintendo Entertainment System (SNES).
static ThemeManager & Get()
#define LOG_ERROR(category, format,...)
std::string MakePopupIdWithInstance(const std::string &editor_name, const std::string &popup_name, const void *instance)
Generate popup ID with instance pointer for guaranteed uniqueness.
ImVec4 ConvertSnesColorToImVec4(const gfx::SnesColor &color)
Convert SnesColor to standard ImVec4 for display.
IMGUI_API bool SnesColorEdit4(absl::string_view label, gfx::SnesColor *color, ImGuiColorEditFlags flags)
SNES color in 15-bit RGB format (BGR555)
PaletteGroup dungeon_main
gfx::PaletteGroupMap palette_groups