6#include "absl/strings/str_format.h"
29 ImGui::TextColored(ImVec4(1, 0, 0, 1),
"ROM not loaded");
51 ImGui::TextDisabled(
"Select a color to edit");
59 int num_palettes = dungeon_pal_group.size();
61 ImGui::Text(
"Dungeon Palette:");
64 if (ImGui::BeginCombo(
67 for (
int i = 0; i < num_palettes; i++) {
69 if (ImGui::Selectable(absl::StrFormat(
"Palette %d", i).c_str(),
75 ImGui::SetItemDefaultFocus();
91 ImGuiColorEditFlags_NoAlpha |
92 ImGuiColorEditFlags_PickerHueWheel)) {
96 uint16_t
snes_color = (b << 10) | (g << 5) | r;
106 ImGui::Text(
"RGB (0-255): (%d, %d, %d)", (
int)(
editing_color_.x * 255),
108 ImGui::Text(
"SNES BGR555: 0x%04X", original_color.snes());
110 if (ImGui::Button(
"Reset to Original")) {
112 original_color.rgb().y / 255.0f,
113 original_color.rgb().z / 255.0f, 1.0f);
120 const std::string &title) {
121 if (ImGui::BeginPopupModal(title.c_str(),
nullptr,
122 ImGuiWindowFlags_AlwaysAutoResize)) {
123 ImGui::Text(
"Enhanced Palette Editor");
129 if (ImGui::CollapsingHeader(
"Palette Analysis")) {
133 if (ImGui::CollapsingHeader(
"ROM Palette Manager") &&
rom_) {
146 if (ImGui::Button(
"Save Backup")) {
150 if (ImGui::Button(
"Restore Backup")) {
154 if (ImGui::Button(
"Close")) {
155 ImGui::CloseCurrentPopup();
167 ImGui::Text(
"No ROM loaded");
180 ImGui::Text(
"Preview of %s:",
192 const std::string &title) {
196 ImGui::Text(
"Bitmap Color Analysis");
200 ImGui::Text(
"Bitmap is not active");
205 std::map<uint8_t, int> pixel_counts;
206 const auto &data = bitmap.
vector();
208 for (uint8_t pixel : data) {
209 uint8_t palette_index = pixel & 0x0F;
210 pixel_counts[palette_index]++;
213 ImGui::Text(
"Bitmap Size: %d x %d (%zu pixels)", bitmap.
width(),
214 bitmap.
height(), data.size());
217 ImGui::Text(
"Pixel Distribution:");
219 int total_pixels =
static_cast<int>(data.size());
220 for (
const auto &[index, count] : pixel_counts) {
221 float percentage = (
static_cast<float>(count) / total_pixels) * 100.0f;
222 ImGui::Text(
"Index %d: %d pixels (%.1f%%)", index, count, percentage);
225 ImGui::ProgressBar(percentage / 100.0f, ImVec2(100, 0));
227 if (index <
static_cast<int>(bitmap.
palette().
size())) {
229 auto color = bitmap.
palette()[index];
230 ImVec4 display_color = color.rgb();
231 ImGui::ColorButton((
"##color" + std::to_string(index)).c_str(),
232 display_color, ImGuiColorEditFlags_NoTooltip,
234 if (ImGui::IsItemHovered()) {
235 ImGui::SetTooltip(
"SNES Color: 0x%04X\nRGB: (%d, %d, %d)",
237 static_cast<int>(display_color.x * 255),
238 static_cast<int>(display_color.y * 255),
239 static_cast<int>(display_color.z * 255));
258 if (palette_index >= 0 && palette_index < 8) {
270 }
catch (
const std::exception &e) {
297 for (
int i = 0; i < static_cast<int>(palette.
size()); i++) {
298 if (i % cols != 0) ImGui::SameLine();
300 auto color = palette[i];
301 ImVec4 display_color = color.rgb();
304 if (ImGui::ColorButton(
"##color", display_color,
305 ImGuiColorEditFlags_NoTooltip, ImVec2(30, 30))) {
312 if (ImGui::BeginPopupContextItem()) {
313 ImGui::Text(
"Color %d (0x%04X)", i, color.snes());
315 if (ImGui::MenuItem(
"Edit Color")) {
321 if (ImGui::MenuItem(
"Reset to Black")) {
327 if (ImGui::IsItemHovered()) {
328 ImGui::SetTooltip(
"Color %d\nSNES: 0x%04X\nRGB: (%d, %d, %d)", i,
329 color.snes(),
static_cast<int>(display_color.x * 255),
330 static_cast<int>(display_color.y * 255),
331 static_cast<int>(display_color.z * 255));
338 ImGui::OpenPopup(
"Edit Color");
339 if (ImGui::BeginPopupModal(
"Edit Color",
nullptr,
340 ImGuiWindowFlags_AlwaysAutoResize)) {
343 ImGuiColorEditFlags_NoAlpha |
344 ImGuiColorEditFlags_DisplayRGB)) {
348 if (ImGui::Button(
"Apply")) {
350 ImGui::CloseCurrentPopup();
353 if (ImGui::Button(
"Cancel")) {
355 ImGui::CloseCurrentPopup();
368 ImGui::Text(
"No ROM palettes available");
372 ImGui::Text(
"Palette Group:");
375 [](
void *data,
int idx,
const char **out_text) ->
bool {
376 auto *names =
static_cast<std::vector<std::string> *
>(data);
377 if (idx < 0 || idx >=
static_cast<int>(names->size()))
return false;
378 *out_text = (*names)[idx].c_str();
385 ImGui::Text(
"Palette Index:");
389 ImGui::Text(
"Preview:");
391 for (
int i = 0; i < 8 && i < static_cast<int>(preview_palette.size());
393 if (i > 0) ImGui::SameLine();
394 auto color = preview_palette[i];
395 ImVec4 display_color = color.rgb();
396 ImGui::ColorButton((
"##preview" + std::to_string(i)).c_str(),
397 display_color, ImGuiColorEditFlags_NoTooltip,
405 ImVec4 rgba = color.
rgb();
407 ImGui::PushID(color_index);
409 if (ImGui::ColorEdit4(
"##color_edit", &rgba.x,
410 ImGuiColorEditFlags_NoAlpha |
411 ImGuiColorEditFlags_DisplayRGB)) {
415 ImGui::Text(
"SNES Color: 0x%04X", color.
snes());
417 int r = (color.
snes() & 0x1F);
418 int g = (color.
snes() >> 5) & 0x1F;
419 int b = (color.
snes() >> 10) & 0x1F;
421 if (ImGui::SliderInt(
"Red", &r, 0, 31)) {
422 uint16_t new_color = (color.
snes() & 0xFFE0) | (r & 0x1F);
425 if (ImGui::SliderInt(
"Green", &g, 0, 31)) {
426 uint16_t new_color = (color.
snes() & 0xFC1F) | ((g & 0x1F) << 5);
429 if (ImGui::SliderInt(
"Blue", &b, 0, 31)) {
430 uint16_t new_color = (color.
snes() & 0x83FF) | ((b & 0x1F) << 10);
439 ImGui::Text(
"Palette Information:");
440 ImGui::Text(
"Size: %zu colors", palette.
size());
442 std::map<uint16_t, int> color_frequency;
443 for (
int i = 0; i < static_cast<int>(palette.
size()); i++) {
444 color_frequency[palette[i].snes()]++;
447 ImGui::Text(
"Unique Colors: %zu", color_frequency.size());
449 if (color_frequency.size() < palette.
size()) {
450 ImGui::TextColored(ImVec4(1, 1, 0, 1),
"Warning: Duplicate colors detected!");
451 if (ImGui::TreeNode(
"Duplicate Colors")) {
452 for (
const auto &[
snes_color, count] : color_frequency) {
455 ImGui::ColorButton((
"##dup" + std::to_string(
snes_color)).c_str(),
456 display_color, ImGuiColorEditFlags_NoTooltip,
459 ImGui::Text(
"0x%04X appears %d times",
snes_color, count);
466 float total_brightness = 0.0f;
467 float min_brightness = 1.0f;
468 float max_brightness = 0.0f;
470 for (
int i = 0; i < static_cast<int>(palette.
size()); i++) {
471 ImVec4 color = palette[i].rgb();
472 float brightness = (color.x + color.y + color.z) / 3.0f;
473 total_brightness += brightness;
474 min_brightness = std::min(min_brightness, brightness);
475 max_brightness = std::max(max_brightness, brightness);
478 float avg_brightness = total_brightness / palette.
size();
481 ImGui::Text(
"Brightness Analysis:");
482 ImGui::Text(
"Average: %.2f", avg_brightness);
483 ImGui::Text(
"Range: %.2f - %.2f", min_brightness, max_brightness);
485 ImGui::Text(
"Brightness Distribution:");
486 ImGui::ProgressBar(avg_brightness, ImVec2(-1, 0),
"Avg");
497 if (palette_groups.overworld_main.size() > 0) {
501 if (palette_groups.overworld_aux.size() > 0) {
505 if (palette_groups.overworld_animated.size() > 0) {
509 if (palette_groups.dungeon_main.size() > 0) {
513 if (palette_groups.global_sprites.size() > 0) {
517 if (palette_groups.armors.size() > 0) {
521 if (palette_groups.swords.size() > 0) {
527 }
catch (
const std::exception &e) {
528 LOG_ERROR(
"Enhanced Palette Editor",
"Failed to load ROM palettes");
The Rom class is used to load, save, and modify Rom data.
auto palette_group() const
auto mutable_palette_group()
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.
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).
#define LOG_ERROR(category, format,...)
Main namespace for the application.
SNES color in 15-bit RGB format (BGR555)